实现FXAA

main
wuyize 2024-02-25 19:50:35 +08:00
parent bc118b0a20
commit fc75668c68
14 changed files with 2233 additions and 113 deletions

1
.gitignore vendored
View File

@ -363,3 +363,4 @@ MigrationBackup/
FodyWeavers.xsd
/UnitTest/Qt.x64.runsettings
/ArchitectureColoredPainting/ClassDiagram.cd
/ArchitectureColoredPainting/res/Shaders/Fxaa3_11.glsl

View File

@ -213,6 +213,7 @@
<None Include="res\Shaders\skybox.frag" />
<None Include="res\Shaders\skybox.vert" />
<None Include="res\Shaders\ssgi.comp" />
<None Include="res\Shaders\tone_mapping.comp" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="src\Editor\EditorWidgetComponent\StrokeStyleWidget.h" />

View File

@ -464,6 +464,7 @@
<None Include="res\Shaders\pageId_downsample.comp">
<Filter>Resource Files\Shaders</Filter>
</None>
<None Include="res\Shaders\tone_mapping.comp" />
</ItemGroup>
<ItemGroup>
<QtUic Include="EditorWidgetItem.ui">

View File

@ -81,6 +81,16 @@
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="fxaaCheckBox">
<property name="text">
<string>FXAA</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -32,6 +32,7 @@
<file>Shaders/cubemap_prefilter.frag</file>
<file>Shaders/brdf_lut.comp</file>
<file>Shaders/pageId_downsample.comp</file>
<file>Shaders/tone_mapping.comp</file>
</qresource>
<qresource prefix="/qt/etc">
<file>qt.conf</file>

File diff suppressed because it is too large Load Diff

View File

@ -184,22 +184,15 @@ void main()
{
ivec2 pixelLocation = ivec2(gl_GlobalInvocationID.xy);
//vec3 albedo = pow(texelFetch(gBaseColor, pixelLocation, 0).rgb, vec3(2.2));
vec3 albedo = pow(imageLoad(gBaseColor, pixelLocation).rgb, vec3(2.2));
vec4 baseColor = imageLoad(gBaseColor, pixelLocation);
if(baseColor.a == 0) return;
vec3 albedo = pow(baseColor.rgb, vec3(2.2));
float metallic = texelFetch(gMetallicRoughness, pixelLocation, 0).r;
float roughness = texelFetch(gMetallicRoughness, pixelLocation, 0).g;
vec3 worldPos = texelFetch(gPosition, pixelLocation,0).xyz;
vec3 normal = texelFetch(gNormal, pixelLocation,0).xyz;
if(normal==vec3(0))
{
//vec3 color = mainLightRadiance;
//imageStore(gBaseColor, pixelLocation, vec4(color, 1.0));
imageStore(gBaseColor, pixelLocation, vec4(0));
return;
}
normal = normalize(normal);
vec3 V = normalize(camPos - worldPos);

View File

@ -1,32 +1,24 @@
#version 450 core
out vec4 FragColor;
layout (location = 0) out vec4 FragColor;
in vec3 WorldPos;
uniform samplerCube environmentMap;
uniform float exposure = 1;
vec3 ACESToneMapping(vec3 color)
vec4 encodeRGBM(vec3 color)
{
const float A = 2.51;
const float B = 0.03;
const float C = 2.43;
const float D = 0.59;
const float E = 0.14;
return (color * (A * color + B)) / (color * (C * color + D) + E);
if(dot(color,color)==0)
return vec4(0,0,0,1);
vec4 rgbm;
float range = 8;
color /= range;
rgbm.a = clamp(max(max(color.r, color.g), max(color.b, 1e-6)), 0.0, 1.0);
rgbm.a = ceil(rgbm.a * 255.0) / 255.0;
rgbm.rgb = color / rgbm.a;
return rgbm;
}
void main()
{
vec3 color = texture(environmentMap, WorldPos).rgb;
// HDR tonemap
//envColor = envColor / (envColor + vec3(1.0));
color *= exposure;
color = ACESToneMapping(color);
// gamma correct
color = pow(color, vec3(1.0/2.2));
FragColor = vec4(color, 1.0);
FragColor = encodeRGBM(color);
}

View File

@ -0,0 +1,28 @@
#version 450 core
layout (local_size_x = 8, local_size_y = 8) in;
layout(rgba8, binding = 0) uniform image2D gBaseColor;
uniform float exposure = 1;
vec3 ACESToneMapping(vec3 color)
{
const float A = 2.51;
const float B = 0.03;
const float C = 2.43;
const float D = 0.59;
const float E = 0.14;
return (color * (A * color + B)) / (color * (C * color + D) + E);
}
void main()
{
ivec2 pixelLocation = ivec2(gl_GlobalInvocationID.xy);
vec4 rgbm = imageLoad(gBaseColor, pixelLocation);
vec3 color = 8 * rgbm.rgb * rgbm.a;
color *= exposure;
color = ACESToneMapping(color);
float luma = sqrt(dot(color.rgb, vec3(0.299, 0.587, 0.114)));
imageStore(gBaseColor, pixelLocation, vec4(color, luma));
}

View File

@ -185,13 +185,60 @@ namespace Renderer
pbrShader.release();
}
FinalPass::FinalPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor, float& exposure)
SkyboxPass::SkyboxPass(GladGLContext* gl, QOpenGLFramebufferObject*& fbo, QMatrix4x4& projection, QMatrix4x4& view, GLuint& skyCubemap)
: RenderPass(gl)
, skyBoxShader(":Shaders/skybox.vert", ":Shaders/skybox.frag")
, fbo(fbo)
, projection(projection)
, view(view)
, skyCubemap(skyCubemap)
{
skyBoxShader.bind();
skyBoxShader.setUniformValue("environmentMap", environmentMapBinding);
skyBoxShader.release();
}
void SkyboxPass::dispatch()
{
if (fbo->bind())
{
skyBoxShader.bind();
gl->Disable(GL_CULL_FACE);
skyBoxShader.setUniformValue("view", view);
skyBoxShader.setUniformValue("projection", projection);
gl->BindTextureUnit(environmentMapBinding, skyCubemap);
IblUtils::renderCube(gl);
skyBoxShader.release();
fbo->release();
}
}
ToneMappingPass::ToneMappingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor, float& exposure)
: RenderPass(gl)
, toneMappingShader(":Shaders/tone_mapping.comp")
, frameWidth(frameWidth)
, frameHeight(frameHeight)
, gBaseColor(gBaseColor)
, exposure(exposure)
{}
void ToneMappingPass::dispatch()
{
toneMappingShader.bind();
toneMappingShader.setUniformValue("exposure", exposure);
gl->BindImageTexture(0, gBaseColor, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
gl->DispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
toneMappingShader.release();
}
FinalPass::FinalPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor)
: RenderPass(gl)
, finalShader(":Shaders/final.vert", ":Shaders/final.frag")
, frameWidth(frameWidth)
, frameHeight(frameHeight)
, gBaseColor(gBaseColor)
, exposure(exposure)
{
finalShader.bind();
finalShader.setUniformValue("gBaseColor", gBaseColorBinding);
@ -226,7 +273,8 @@ namespace Renderer
gl->Viewport(0, 0, frameWidth, frameHeight);
gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
finalShader.bind();
finalShader.setUniformValue("exposure", exposure);
finalShader.setUniformValue("enableFxaa", enableFxaa);
finalShader.setUniformValue("RCPFrame", QVector2D(1.f / frameWidth, 1.f / frameHeight));
gl->BindTextureUnit(gBaseColorBinding, gBaseColor);
quadVAO.bind();
gl->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@ -234,28 +282,8 @@ namespace Renderer
finalShader.release();
}
SkyboxPass::SkyboxPass(GladGLContext* gl, QMatrix4x4& projection, QMatrix4x4& view, float& exposure, GLuint& skyCubemap)
: RenderPass(gl)
, skyBoxShader(":Shaders/skybox.vert", ":Shaders/skybox.frag")
, projection(projection)
, view(view)
, exposure(exposure)
, skyCubemap(skyCubemap)
void FinalPass::setEnableFxaa(bool enable)
{
skyBoxShader.bind();
skyBoxShader.setUniformValue("environmentMap", environmentMapBinding);
skyBoxShader.release();
}
void SkyboxPass::dispatch()
{
skyBoxShader.bind();
gl->Disable(GL_CULL_FACE);
skyBoxShader.setUniformValue("view", view);
skyBoxShader.setUniformValue("projection", projection);
skyBoxShader.setUniformValue("exposure", exposure);
gl->BindTextureUnit(environmentMapBinding, skyCubemap);
IblUtils::renderCube(gl);
skyBoxShader.release();
enableFxaa = enable;
}
}

View File

@ -98,35 +98,52 @@ namespace Renderer
brdfLUTBinding = 7;
};
class SkyboxPass : public RenderPass
{
public:
SkyboxPass(GladGLContext* gl, QOpenGLFramebufferObject*& fbo, QMatrix4x4& projection, QMatrix4x4& view, GLuint& skyCubemap);
void dispatch();
private:
Shader skyBoxShader;
QOpenGLFramebufferObject*& fbo;
QMatrix4x4& projection;
QMatrix4x4& view;
GLuint& skyCubemap;
constexpr static GLint environmentMapBinding = 0;
};
class ToneMappingPass : public RenderPass
{
public:
ToneMappingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor, float& exposure);
void dispatch();
private:
Shader toneMappingShader;
unsigned int& frameWidth;
unsigned int& frameHeight;
GLuint& gBaseColor;
float& exposure;
};
class FinalPass : public RenderPass
{
public:
FinalPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor, float& exposure);
FinalPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor);
void dispatch();
void setEnableFxaa(bool enable);
private:
Shader finalShader;
unsigned int& frameWidth;
unsigned int& frameHeight;
GLuint& gBaseColor;
float& exposure;
QOpenGLBuffer quadVBO;
QOpenGLVertexArrayObject quadVAO;
constexpr static GLint gBaseColorBinding = 0;
bool enableFxaa = true;
};
class SkyboxPass : public RenderPass
{
public:
SkyboxPass(GladGLContext* gl, QMatrix4x4& projection, QMatrix4x4& view, float& exposure, GLuint& skyCubemap);
void dispatch();
private:
Shader skyBoxShader;
QMatrix4x4& projection;
QMatrix4x4& view;
float& exposure;
GLuint& skyCubemap;
constexpr static GLint environmentMapBinding = 0;
};
}

View File

@ -92,6 +92,11 @@ void Renderer::RendererGLWidget::setExposure(float exposure)
this->exposure = exposure;
}
void Renderer::RendererGLWidget::setEnableFxaa(bool enable)
{
finalPass->setEnableFxaa(enable);
}
QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
void GLAPIENTRY messageCallback(GLenum source,
@ -126,7 +131,7 @@ void RendererGLWidget::initializeGL()
gl->Enable(GL_DEPTH_TEST);
gl->DepthFunc(GL_LEQUAL);
gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
gl->ClearColor(0, 0, 0, 1);
gl->ClearColor(0, 0, 0, 0);
vtManager = std::make_unique<VirtualTextureManager>(gl.get());
model = new Model(context(), vtManager.get());
@ -136,8 +141,10 @@ void RendererGLWidget::initializeGL()
pageIDCallbackPass = std::make_unique<PageIDCallbackPass>(gl.get(), frameWidth, frameHeight, fboPtr, gbuffers, gPageID, *vtManager);
lightingPass = std::make_unique<LightingPass>(gl.get(), frameWidth, frameHeight, view, camera, light,
gBaseColor, gNormal, gPosition, gMetallicRoughness, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture);
finalPass = std::make_unique<FinalPass>(gl.get(), frameWidth, frameHeight, gBaseColor, exposure);
skyboxPass = std::make_unique<SkyboxPass>(gl.get(), projection, view, exposure, skyCubemap);
skyboxPass = std::make_unique<SkyboxPass>(gl.get(), fboPtr, projection, view, skyCubemap);
toneMappingPass = std::make_unique<ToneMappingPass>(gl.get(), frameWidth, frameHeight, gBaseColor, exposure);
finalPass = std::make_unique<FinalPass>(gl.get(), frameWidth, frameHeight, gBaseColor);
depthInitProgramPtr = new QOpenGLShaderProgram;
if (!depthInitProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_init.comp"))
@ -207,8 +214,10 @@ void RendererGLWidget::paintGL()
gl->Finish();
vtManager->commitMutex.unlock();
lightingPass->dispatch();
finalPass->dispatch();
skyboxPass->dispatch();
toneMappingPass->dispatch();
finalPass->dispatch();
gl->EndQuery(GL_TIME_ELAPSED);
GLuint frameDuration;
@ -270,6 +279,9 @@ void RendererGLWidget::resizeGL(int width, int height)
{
//BaseColor
gbuffers[0] = fboPtr->texture();
gl->BindTexture(GL_TEXTURE_2D, gbuffers[0]);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->GenTextures(9, gbuffers + 1);
//Normal

View File

@ -34,6 +34,7 @@ namespace Renderer
void setMainLightPitch(float pitch);
void setMainLightYaw(float yaw);
void setExposure(float exposure);
void setEnableFxaa(bool enable);
protected:
void initializeGL() override;
void paintGL() override;
@ -64,8 +65,10 @@ namespace Renderer
std::unique_ptr<GeometryPass> geometryPass;
std::unique_ptr<PageIDCallbackPass> pageIDCallbackPass;
std::unique_ptr<LightingPass> lightingPass;
std::unique_ptr<FinalPass> finalPass;
std::unique_ptr<SkyboxPass> skyboxPass;
std::unique_ptr<ToneMappingPass> toneMappingPass;
std::unique_ptr<FinalPass> finalPass;
QOpenGLShaderProgram* depthInitProgramPtr = nullptr;
QOpenGLShaderProgram* depthMipmapProgramPtr = nullptr;

View File

@ -65,6 +65,10 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent)
emit openPaintingFile(paintingPath);
});
QObject::connect(ui.fxaaCheckBox, &QCheckBox::toggled, this, [&](bool checked) {
ui.openGLWidget->setEnableFxaa(checked);
});
QObject::connect(ui.lightRadianceSlider, &QSlider::valueChanged, [&](int value) {
ui.openGLWidget->setMainLightRadiance(value / 10.f * QVector3D(0.7529, 0.7450, 0.6784).normalized());
});