mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
Merge branch 'ssao' of https://github.com/dpjudas/dpDoom
This commit is contained in:
commit
a825d1d92f
31 changed files with 1385 additions and 215 deletions
|
@ -963,6 +963,7 @@ set( FASTMATH_SOURCES
|
|||
gl/shaders/gl_presentshader.cpp
|
||||
gl/shaders/gl_present3dRowshader.cpp
|
||||
gl/shaders/gl_bloomshader.cpp
|
||||
gl/shaders/gl_ambientshader.cpp
|
||||
gl/shaders/gl_blurshader.cpp
|
||||
gl/shaders/gl_colormapshader.cpp
|
||||
gl/shaders/gl_tonemapshader.cpp
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "gl/renderer/gl_postprocessstate.h"
|
||||
#include "gl/data/gl_data.h"
|
||||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/shaders/gl_ambientshader.h"
|
||||
#include "gl/shaders/gl_bloomshader.h"
|
||||
#include "gl/shaders/gl_blurshader.h"
|
||||
#include "gl/shaders/gl_tonemapshader.h"
|
||||
|
@ -106,6 +107,32 @@ CUSTOM_CVAR(Int, gl_fxaa, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, gl_ssao, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0 || self > 3)
|
||||
self = 0;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, gl_ssao_portals, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
}
|
||||
|
||||
CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, gl_ssao_debug, 0, 0)
|
||||
CVAR(Float, gl_ssao_bias, 0.2f, 0)
|
||||
CVAR(Float, gl_ssao_radius, 80.0f, 0)
|
||||
CUSTOM_CVAR(Float, gl_ssao_blur, 16.0f, 0)
|
||||
{
|
||||
if (self < 0.1f) self = 0.1f;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, gl_ssao_exponent, 1.8f, 0)
|
||||
{
|
||||
if (self < 0.1f) self = 0.1f;
|
||||
}
|
||||
|
||||
EXTERN_CVAR(Float, vid_brightness)
|
||||
EXTERN_CVAR(Float, vid_contrast)
|
||||
|
||||
|
@ -117,6 +144,153 @@ void FGLRenderer::RenderScreenQuad()
|
|||
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4);
|
||||
}
|
||||
|
||||
void FGLRenderer::PostProcessScene()
|
||||
{
|
||||
mBuffers->BlitSceneToTexture();
|
||||
UpdateCameraExposure();
|
||||
BloomScene();
|
||||
TonemapScene();
|
||||
ColormapScene();
|
||||
LensDistortScene();
|
||||
ApplyFXAA();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Adds ambient occlusion to the scene
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FGLRenderer::AmbientOccludeScene()
|
||||
{
|
||||
FGLDebug::PushGroup("AmbientOccludeScene");
|
||||
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(3);
|
||||
|
||||
float bias = gl_ssao_bias;
|
||||
float aoRadius = gl_ssao_radius;
|
||||
const float blurAmount = gl_ssao_blur;
|
||||
float aoStrength = gl_ssao_strength;
|
||||
|
||||
//float tanHalfFovy = tan(fovy * (M_PI / 360.0f));
|
||||
float tanHalfFovy = 1.0f / gl_RenderState.mProjectionMatrix.get()[5];
|
||||
float invFocalLenX = tanHalfFovy * (mBuffers->GetSceneWidth() / (float)mBuffers->GetSceneHeight());
|
||||
float invFocalLenY = tanHalfFovy;
|
||||
float nDotVBias = clamp(bias, 0.0f, 1.0f);
|
||||
float r2 = aoRadius * aoRadius;
|
||||
|
||||
float blurSharpness = 1.0f / blurAmount;
|
||||
|
||||
float sceneScaleX = mSceneViewport.width / (float)mScreenViewport.width;
|
||||
float sceneScaleY = mSceneViewport.height / (float)mScreenViewport.height;
|
||||
float sceneOffsetX = mSceneViewport.left / (float)mScreenViewport.width;
|
||||
float sceneOffsetY = mSceneViewport.top / (float)mScreenViewport.height;
|
||||
|
||||
int randomTexture = clamp(gl_ssao - 1, 0, FGLRenderBuffers::NumAmbientRandomTextures - 1);
|
||||
|
||||
// Calculate linear depth values
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->LinearDepthFB);
|
||||
glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight);
|
||||
mBuffers->BindSceneDepthTexture(0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
mBuffers->BindSceneColorTexture(1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
mLinearDepthShader->Bind();
|
||||
mLinearDepthShader->DepthTexture.Set(0);
|
||||
mLinearDepthShader->ColorTexture.Set(1);
|
||||
if (gl_multisample > 1) mLinearDepthShader->SampleIndex.Set(0);
|
||||
mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear());
|
||||
mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f));
|
||||
mLinearDepthShader->InverseDepthRangeA.Set(1.0f);
|
||||
mLinearDepthShader->InverseDepthRangeB.Set(0.0f);
|
||||
mLinearDepthShader->Scale.Set(sceneScaleX, sceneScaleY);
|
||||
mLinearDepthShader->Offset.Set(sceneOffsetX, sceneOffsetY);
|
||||
RenderScreenQuad();
|
||||
|
||||
// Apply ambient occlusion
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1);
|
||||
glBindTexture(GL_TEXTURE_2D, mBuffers->LinearDepthTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientRandomTexture[randomTexture]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
mBuffers->BindSceneNormalTexture(2);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
mSSAOShader->Bind();
|
||||
mSSAOShader->DepthTexture.Set(0);
|
||||
mSSAOShader->RandomTexture.Set(1);
|
||||
mSSAOShader->NormalTexture.Set(2);
|
||||
if (gl_multisample > 1) mSSAOShader->SampleIndex.Set(0);
|
||||
mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, 2.0f * invFocalLenY);
|
||||
mSSAOShader->UVToViewB.Set(-invFocalLenX, -invFocalLenY);
|
||||
mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight);
|
||||
mSSAOShader->NDotVBias.Set(nDotVBias);
|
||||
mSSAOShader->NegInvR2.Set(-1.0f / r2);
|
||||
mSSAOShader->RadiusToScreen.Set(aoRadius * 0.5 / tanHalfFovy * mBuffers->AmbientHeight);
|
||||
mSSAOShader->AOMultiplier.Set(1.0f / (1.0f - nDotVBias));
|
||||
mSSAOShader->AOStrength.Set(aoStrength);
|
||||
mSSAOShader->Scale.Set(sceneScaleX, sceneScaleY);
|
||||
mSSAOShader->Offset.Set(sceneOffsetX, sceneOffsetY);
|
||||
RenderScreenQuad();
|
||||
|
||||
// Blur SSAO texture
|
||||
if (gl_ssao_debug < 2)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0);
|
||||
glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
mDepthBlurShader->Bind(false);
|
||||
mDepthBlurShader->BlurSharpness[false].Set(blurSharpness);
|
||||
mDepthBlurShader->InvFullResolution[false].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight);
|
||||
RenderScreenQuad();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1);
|
||||
glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0);
|
||||
mDepthBlurShader->Bind(true);
|
||||
mDepthBlurShader->BlurSharpness[true].Set(blurSharpness);
|
||||
mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight);
|
||||
mDepthBlurShader->PowExponent[true].Set(gl_ssao_exponent);
|
||||
RenderScreenQuad();
|
||||
}
|
||||
|
||||
// Add SSAO back to scene texture:
|
||||
mBuffers->BindSceneFB(false);
|
||||
glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (gl_ssao_debug != 0)
|
||||
{
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
mBuffers->BindSceneFogTexture(1);
|
||||
mSSAOCombineShader->Bind();
|
||||
mSSAOCombineShader->AODepthTexture.Set(0);
|
||||
mSSAOCombineShader->SceneFogTexture.Set(1);
|
||||
if (gl_multisample > 1) mSSAOCombineShader->SampleCount.Set(gl_multisample);
|
||||
mSSAOCombineShader->Scale.Set(sceneScaleX, sceneScaleY);
|
||||
mSSAOCombineShader->Offset.Set(sceneOffsetX, sceneOffsetY);
|
||||
RenderScreenQuad();
|
||||
|
||||
FGLDebug::PopGroup();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Extracts light average from the scene and updates the camera exposure texture
|
||||
|
@ -131,7 +305,7 @@ void FGLRenderer::UpdateCameraExposure()
|
|||
FGLDebug::PushGroup("UpdateCameraExposure");
|
||||
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBinding1();
|
||||
savedState.SaveTextureBindings(2);
|
||||
|
||||
// Extract light level from scene texture:
|
||||
const auto &level0 = mBuffers->ExposureLevels[0];
|
||||
|
@ -198,13 +372,13 @@ void FGLRenderer::UpdateCameraExposure()
|
|||
void FGLRenderer::BloomScene()
|
||||
{
|
||||
// Only bloom things if enabled and no special fixed light mode is active
|
||||
if (!gl_bloom || gl_fixedcolormap != CM_DEFAULT)
|
||||
if (!gl_bloom || gl_fixedcolormap != CM_DEFAULT || gl_ssao_debug)
|
||||
return;
|
||||
|
||||
FGLDebug::PushGroup("BloomScene");
|
||||
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBinding1();
|
||||
savedState.SaveTextureBindings(2);
|
||||
|
||||
const float blurAmount = gl_bloom_amount;
|
||||
int sampleCount = gl_bloom_kernel_size;
|
||||
|
@ -293,7 +467,10 @@ void FGLRenderer::TonemapScene()
|
|||
|
||||
FGLDebug::PushGroup("TonemapScene");
|
||||
|
||||
CreateTonemapPalette();
|
||||
|
||||
FGLPostProcessState savedState;
|
||||
savedState.SaveTextureBindings(2);
|
||||
|
||||
mBuffers->BindNextFB();
|
||||
mBuffers->BindCurrentTexture(0);
|
||||
|
@ -302,12 +479,18 @@ void FGLRenderer::TonemapScene()
|
|||
|
||||
if (mTonemapShader->IsPaletteMode())
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, mTonemapPalette->GetTextureHandle(0));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
mTonemapShader->PaletteLUT.Set(1);
|
||||
BindTonemapPalette(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
savedState.SaveTextureBinding1();
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureTexture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -321,13 +504,9 @@ void FGLRenderer::TonemapScene()
|
|||
FGLDebug::PopGroup();
|
||||
}
|
||||
|
||||
void FGLRenderer::BindTonemapPalette(int texunit)
|
||||
void FGLRenderer::CreateTonemapPalette()
|
||||
{
|
||||
if (mTonemapPalette)
|
||||
{
|
||||
mTonemapPalette->Bind(texunit, 0, false);
|
||||
}
|
||||
else
|
||||
if (!mTonemapPalette)
|
||||
{
|
||||
TArray<unsigned char> lut;
|
||||
lut.Resize(512 * 512 * 4);
|
||||
|
@ -348,14 +527,7 @@ void FGLRenderer::BindTonemapPalette(int texunit)
|
|||
}
|
||||
|
||||
mTonemapPalette = new FHardwareTexture(512, 512, true);
|
||||
mTonemapPalette->CreateTexture(&lut[0], 512, 512, texunit, false, 0, "mTonemapPalette");
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + texunit);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
mTonemapPalette->CreateTexture(&lut[0], 512, 512, 0, false, 0, "mTonemapPalette");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,7 +597,7 @@ void FGLRenderer::LensDistortScene()
|
|||
0.0f
|
||||
};
|
||||
|
||||
float aspect = mSceneViewport.width / mSceneViewport.height;
|
||||
float aspect = mSceneViewport.width / (float)mSceneViewport.height;
|
||||
|
||||
// Scale factor to keep sampling within the input texture
|
||||
float r2 = aspect * aspect * 0.25 + 0.25f;
|
||||
|
|
|
@ -45,17 +45,7 @@ FGLPostProcessState::FGLPostProcessState()
|
|||
{
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[0]);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
if (gl.flags & RFL_SAMPLER_OBJECTS)
|
||||
{
|
||||
glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[0]);
|
||||
glBindSampler(0, 0);
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[1]);
|
||||
glBindSampler(1, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
SaveTextureBindings(1);
|
||||
|
||||
glGetBooleanv(GL_BLEND, &blendEnabled);
|
||||
glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled);
|
||||
|
@ -75,12 +65,26 @@ FGLPostProcessState::FGLPostProcessState()
|
|||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void FGLPostProcessState::SaveTextureBinding1()
|
||||
void FGLPostProcessState::SaveTextureBindings(unsigned int numUnits)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[1]);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
textureBinding1Saved = true;
|
||||
while (textureBinding.Size() < numUnits)
|
||||
{
|
||||
unsigned int i = textureBinding.Size();
|
||||
|
||||
GLint texture;
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
textureBinding.Push(texture);
|
||||
|
||||
if (gl.flags & RFL_SAMPLER_OBJECTS)
|
||||
{
|
||||
GLint sampler;
|
||||
glGetIntegerv(GL_SAMPLER_BINDING, &sampler);
|
||||
glBindSampler(i, 0);
|
||||
samplerBinding.Push(sampler);
|
||||
}
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
|
@ -117,25 +121,22 @@ FGLPostProcessState::~FGLPostProcessState()
|
|||
|
||||
glUseProgram(currentProgram);
|
||||
|
||||
if (textureBinding1Saved)
|
||||
// Fully unbind to avoid incomplete texture warnings from Nvidia's driver when gl_debug_level 4 is active
|
||||
for (unsigned int i = 0; i < textureBinding.Size(); i++)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
if (gl.flags & RFL_SAMPLER_OBJECTS)
|
||||
for (unsigned int i = 0; i < samplerBinding.Size(); i++)
|
||||
{
|
||||
glBindSampler(0, samplerBinding[0]);
|
||||
glBindSampler(1, samplerBinding[1]);
|
||||
glBindSampler(i, samplerBinding[i]);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, textureBinding[0]);
|
||||
|
||||
if (textureBinding1Saved)
|
||||
for (unsigned int i = 0; i < textureBinding.Size(); i++)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, textureBinding[1]);
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, textureBinding[i]);
|
||||
}
|
||||
|
||||
glActiveTexture(activeTex);
|
||||
|
|
|
@ -14,15 +14,15 @@ public:
|
|||
FGLPostProcessState();
|
||||
~FGLPostProcessState();
|
||||
|
||||
void SaveTextureBinding1();
|
||||
void SaveTextureBindings(unsigned int numUnits);
|
||||
|
||||
private:
|
||||
FGLPostProcessState(const FGLPostProcessState &) = delete;
|
||||
FGLPostProcessState &operator=(const FGLPostProcessState &) = delete;
|
||||
|
||||
GLint activeTex;
|
||||
GLint textureBinding[2];
|
||||
GLint samplerBinding[2];
|
||||
TArray<GLint> textureBinding;
|
||||
TArray<GLint> samplerBinding;
|
||||
GLboolean blendEnabled;
|
||||
GLboolean scissorEnabled;
|
||||
GLboolean depthEnabled;
|
||||
|
@ -34,7 +34,6 @@ private:
|
|||
GLint blendSrcAlpha;
|
||||
GLint blendDestRgb;
|
||||
GLint blendDestAlpha;
|
||||
bool textureBinding1Saved = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "w_wad.h"
|
||||
#include "i_system.h"
|
||||
#include "doomerrors.h"
|
||||
#include <random>
|
||||
|
||||
CVAR(Int, gl_multisample, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
CVAR(Bool, gl_renderbuffers, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
|
@ -58,6 +59,11 @@ FGLRenderBuffers::FGLRenderBuffers()
|
|||
mPipelineFB[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumAmbientRandomTextures; i++)
|
||||
{
|
||||
AmbientRandomTexture[i] = 0;
|
||||
}
|
||||
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&mOutputFB);
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
|
||||
}
|
||||
|
@ -75,15 +81,27 @@ FGLRenderBuffers::~FGLRenderBuffers()
|
|||
ClearEyeBuffers();
|
||||
ClearBloom();
|
||||
ClearExposureLevels();
|
||||
ClearAmbientOcclusion();
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearScene()
|
||||
{
|
||||
DeleteFrameBuffer(mSceneFB);
|
||||
DeleteRenderBuffer(mSceneMultisample);
|
||||
DeleteRenderBuffer(mSceneDepthStencil);
|
||||
DeleteRenderBuffer(mSceneDepth);
|
||||
DeleteRenderBuffer(mSceneStencil);
|
||||
DeleteFrameBuffer(mSceneDataFB);
|
||||
if (mSceneUsesTextures)
|
||||
{
|
||||
DeleteTexture(mSceneMultisample);
|
||||
DeleteTexture(mSceneFog);
|
||||
DeleteTexture(mSceneNormal);
|
||||
DeleteTexture(mSceneDepthStencil);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteRenderBuffer(mSceneMultisample);
|
||||
DeleteRenderBuffer(mSceneFog);
|
||||
DeleteRenderBuffer(mSceneNormal);
|
||||
DeleteRenderBuffer(mSceneDepthStencil);
|
||||
}
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearPipeline()
|
||||
|
@ -132,6 +150,18 @@ void FGLRenderBuffers::ClearEyeBuffers()
|
|||
mEyeFBs.Clear();
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearAmbientOcclusion()
|
||||
{
|
||||
DeleteFrameBuffer(LinearDepthFB);
|
||||
DeleteFrameBuffer(AmbientFB0);
|
||||
DeleteFrameBuffer(AmbientFB1);
|
||||
DeleteTexture(LinearDepthTexture);
|
||||
DeleteTexture(AmbientTexture0);
|
||||
DeleteTexture(AmbientTexture1);
|
||||
for (int i = 0; i < NumAmbientRandomTextures; i++)
|
||||
DeleteTexture(AmbientRandomTexture[i]);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::DeleteTexture(GLuint &handle)
|
||||
{
|
||||
if (handle != 0)
|
||||
|
@ -177,6 +207,7 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei
|
|||
I_FatalError("Requested invalid render buffer sizes: screen = %dx%d", width, height);
|
||||
|
||||
int samples = clamp((int)gl_multisample, 0, mMaxSamples);
|
||||
bool needsSceneTextures = (gl_ssao != 0);
|
||||
|
||||
GLint activeTex;
|
||||
GLint textureBinding;
|
||||
|
@ -184,25 +215,23 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
|
||||
|
||||
if (width == mWidth && height == mHeight && mSamples != samples)
|
||||
{
|
||||
CreateScene(mWidth, mHeight, samples);
|
||||
mSamples = samples;
|
||||
}
|
||||
else if (width != mWidth || height != mHeight)
|
||||
{
|
||||
if (width != mWidth || height != mHeight)
|
||||
CreatePipeline(width, height);
|
||||
CreateScene(width, height, samples);
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mSamples = samples;
|
||||
}
|
||||
|
||||
if (width != mWidth || height != mHeight || mSamples != samples || mSceneUsesTextures != needsSceneTextures)
|
||||
CreateScene(width, height, samples, needsSceneTextures);
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mSamples = samples;
|
||||
mSceneUsesTextures = needsSceneTextures;
|
||||
|
||||
// Bloom bluring buffers need to match the scene to avoid bloom bleeding artifacts
|
||||
if (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight)
|
||||
{
|
||||
CreateBloom(sceneWidth, sceneHeight);
|
||||
CreateExposureLevels(sceneWidth, sceneHeight);
|
||||
CreateAmbientOcclusion(sceneWidth, sceneHeight);
|
||||
mSceneWidth = sceneWidth;
|
||||
mSceneHeight = sceneHeight;
|
||||
}
|
||||
|
@ -235,15 +264,46 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::CreateScene(int width, int height, int samples)
|
||||
void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool needsSceneTextures)
|
||||
{
|
||||
ClearScene();
|
||||
|
||||
if (samples > 1)
|
||||
mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, samples, width, height);
|
||||
|
||||
mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1);
|
||||
{
|
||||
if (needsSceneTextures)
|
||||
{
|
||||
mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false);
|
||||
mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false);
|
||||
mSceneFog = Create2DMultisampleTexture("SceneFog", GL_RGBA8, width, height, samples, false);
|
||||
mSceneNormal = Create2DMultisampleTexture("SceneNormal", GL_RGB10_A2, width, height, samples, false);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, 0, 0, mSceneDepthStencil, true);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisample, mSceneFog, mSceneNormal, mSceneDepthStencil, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, width, height, samples);
|
||||
mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, mSceneDepthStencil, true);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisample, mSceneDepthStencil, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (needsSceneTextures)
|
||||
{
|
||||
mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height);
|
||||
mSceneFog = Create2DTexture("SceneFog", GL_RGBA8, width, height);
|
||||
mSceneNormal = Create2DTexture("SceneNormal", GL_RGB10_A2, width, height);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], 0, 0, mSceneDepthStencil, false);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneFog, mSceneNormal, mSceneDepthStencil, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mSceneDepthStencil, false);
|
||||
mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneDepthStencil, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -278,13 +338,13 @@ void FGLRenderBuffers::CreateBloom(int width, int height)
|
|||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
int bloomWidth = MAX(width / 2, 1);
|
||||
int bloomHeight = MAX(height / 2, 1);
|
||||
int bloomWidth = (width + 1) / 2;
|
||||
int bloomHeight = (height + 1) / 2;
|
||||
for (int i = 0; i < NumBloomLevels; i++)
|
||||
{
|
||||
auto &level = BloomLevels[i];
|
||||
level.Width = MAX(bloomWidth / 2, 1);
|
||||
level.Height = MAX(bloomHeight / 2, 1);
|
||||
level.Width = (bloomWidth + 1) / 2;
|
||||
level.Height = (bloomHeight + 1) / 2;
|
||||
|
||||
level.VTexture = Create2DTexture("Bloom.VTexture", GL_RGBA16F, level.Width, level.Height);
|
||||
level.HTexture = Create2DTexture("Bloom.HTexture", GL_RGBA16F, level.Width, level.Height);
|
||||
|
@ -296,6 +356,55 @@ void FGLRenderBuffers::CreateBloom(int width, int height)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates ambient occlusion working buffers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height)
|
||||
{
|
||||
ClearAmbientOcclusion();
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
AmbientWidth = (width + 1) / 2;
|
||||
AmbientHeight = (height + 1) / 2;
|
||||
LinearDepthTexture = Create2DTexture("LinearDepthTexture", GL_R32F, AmbientWidth, AmbientHeight);
|
||||
AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RG16F, AmbientWidth, AmbientHeight);
|
||||
AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG16F, AmbientWidth, AmbientHeight);
|
||||
LinearDepthFB = CreateFrameBuffer("LinearDepthFB", LinearDepthTexture);
|
||||
AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0);
|
||||
AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1);
|
||||
|
||||
// Must match quality enum in FSSAOShader::GetDefines
|
||||
double numDirections[NumAmbientRandomTextures] = { 2.0, 4.0, 8.0 };
|
||||
|
||||
std::mt19937 generator(1337);
|
||||
std::uniform_real_distribution<double> distribution(0.0, 1.0);
|
||||
for (int quality = 0; quality < NumAmbientRandomTextures; quality++)
|
||||
{
|
||||
int16_t randomValues[16 * 4];
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
double angle = 2.0 * M_PI * distribution(generator) / numDirections[quality];
|
||||
double x = cos(angle);
|
||||
double y = sin(angle);
|
||||
double z = distribution(generator);
|
||||
double w = distribution(generator);
|
||||
|
||||
randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0);
|
||||
randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0);
|
||||
randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0);
|
||||
randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0);
|
||||
}
|
||||
|
||||
AmbientRandomTexture[quality] = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates camera exposure level buffers
|
||||
|
@ -368,12 +477,31 @@ void FGLRenderBuffers::CreateEyeBuffers(int eye)
|
|||
|
||||
GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data)
|
||||
{
|
||||
GLuint type = (format == GL_RGBA16F || format == GL_R32F) ? GL_FLOAT : GL_UNSIGNED_BYTE;
|
||||
GLuint handle = 0;
|
||||
glGenTextures(1, &handle);
|
||||
glBindTexture(GL_TEXTURE_2D, handle);
|
||||
FGLDebug::LabelObject(GL_TEXTURE, handle, name);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format != GL_R32F ? GL_RGBA : GL_RED, type, data);
|
||||
|
||||
GLenum dataformat, datatype;
|
||||
switch (format)
|
||||
{
|
||||
case GL_RGBA8: dataformat = GL_RGBA; datatype = GL_UNSIGNED_BYTE; break;
|
||||
case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break;
|
||||
case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
||||
case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
||||
case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break;
|
||||
case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break;
|
||||
case GL_R16F: dataformat = GL_RED; datatype = GL_FLOAT; break;
|
||||
case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break;
|
||||
case GL_RG16F: dataformat = GL_RG; datatype = GL_FLOAT; break;
|
||||
case GL_RGB10_A2: dataformat = GL_RGBA; datatype = GL_UNSIGNED_INT_10_10_10_2; break;
|
||||
case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break;
|
||||
case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break;
|
||||
case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break;
|
||||
default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture");
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, dataformat, datatype, data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
|
@ -381,6 +509,17 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int
|
|||
return handle;
|
||||
}
|
||||
|
||||
GLuint FGLRenderBuffers::Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations)
|
||||
{
|
||||
GLuint handle = 0;
|
||||
glGenTextures(1, &handle);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, handle);
|
||||
FGLDebug::LabelObject(GL_TEXTURE, handle, name);
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, format, width, height, fixedSampleLocations);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||
return handle;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates a render buffer
|
||||
|
@ -397,7 +536,7 @@ GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format,
|
|||
return handle;
|
||||
}
|
||||
|
||||
GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height)
|
||||
GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, int width, int height, int samples)
|
||||
{
|
||||
if (samples <= 1)
|
||||
return CreateRenderBuffer(name, format, width, height);
|
||||
|
@ -444,18 +583,30 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff
|
|||
return handle;
|
||||
}
|
||||
|
||||
GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer)
|
||||
GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample)
|
||||
{
|
||||
GLuint handle = 0;
|
||||
glGenFramebuffers(1, &handle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, handle);
|
||||
FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name);
|
||||
if (colorIsARenderBuffer)
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
|
||||
if (multisample)
|
||||
{
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer0, 0);
|
||||
if (colorbuffer1 != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer1, 0);
|
||||
if (colorbuffer2 != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer2, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depthstencil, 0);
|
||||
}
|
||||
else
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil);
|
||||
{
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer0, 0);
|
||||
if (colorbuffer1 != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorbuffer1, 0);
|
||||
if (colorbuffer2 != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, colorbuffer2, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0);
|
||||
}
|
||||
if (CheckFrameBufferCompleteness())
|
||||
ClearFrameBuffer(true, true);
|
||||
return handle;
|
||||
|
@ -475,22 +626,23 @@ bool FGLRenderBuffers::CheckFrameBufferCompleteness()
|
|||
|
||||
FailedCreate = true;
|
||||
|
||||
#if 0
|
||||
FString error = "glCheckFramebufferStatus failed: ";
|
||||
switch (result)
|
||||
if (gl_debug_level > 0)
|
||||
{
|
||||
default: error.AppendFormat("error code %d", (int)result); break;
|
||||
case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break;
|
||||
FString error = "glCheckFramebufferStatus failed: ";
|
||||
switch (result)
|
||||
{
|
||||
default: error.AppendFormat("error code %d", (int)result); break;
|
||||
case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break;
|
||||
}
|
||||
Printf("%s\n", error.GetChars());
|
||||
}
|
||||
I_FatalError(error);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -595,9 +747,69 @@ void FGLRenderBuffers::BindEyeFB(int eye, bool readBuffer)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneFB()
|
||||
void FGLRenderBuffers::BindSceneFB(bool sceneData)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sceneData ? mSceneDataFB : mSceneFB);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene color texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneColorTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneMultisample);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mPipelineTexture[0]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene fog data texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneFogTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneFog);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneFog);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene normal data texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneNormalTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneNormal);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneNormal);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the depth texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneDepthTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneDepthStencil);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneDepthStencil);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -31,7 +31,11 @@ public:
|
|||
|
||||
bool Setup(int width, int height, int sceneWidth, int sceneHeight);
|
||||
|
||||
void BindSceneFB();
|
||||
void BindSceneFB(bool sceneData);
|
||||
void BindSceneColorTexture(int index);
|
||||
void BindSceneFogTexture(int index);
|
||||
void BindSceneNormalTexture(int index);
|
||||
void BindSceneDepthTexture(int index);
|
||||
void BlitSceneToTexture();
|
||||
|
||||
void BindCurrentTexture(int index);
|
||||
|
@ -53,28 +57,46 @@ public:
|
|||
GLuint ExposureFB = 0;
|
||||
bool FirstExposureFrame = true;
|
||||
|
||||
// Ambient occlusion buffers
|
||||
GLuint LinearDepthTexture = 0;
|
||||
GLuint LinearDepthFB = 0;
|
||||
GLuint AmbientTexture0 = 0;
|
||||
GLuint AmbientTexture1 = 0;
|
||||
GLuint AmbientFB0 = 0;
|
||||
GLuint AmbientFB1 = 0;
|
||||
int AmbientWidth = 0;
|
||||
int AmbientHeight = 0;
|
||||
enum { NumAmbientRandomTextures = 3 };
|
||||
GLuint AmbientRandomTexture[NumAmbientRandomTextures];
|
||||
|
||||
static bool IsEnabled();
|
||||
|
||||
int GetWidth() const { return mWidth; }
|
||||
int GetHeight() const { return mHeight; }
|
||||
|
||||
int GetSceneWidth() const { return mSceneWidth; }
|
||||
int GetSceneHeight() const { return mSceneHeight; }
|
||||
|
||||
private:
|
||||
void ClearScene();
|
||||
void ClearPipeline();
|
||||
void ClearEyeBuffers();
|
||||
void ClearBloom();
|
||||
void ClearExposureLevels();
|
||||
void CreateScene(int width, int height, int samples);
|
||||
void ClearAmbientOcclusion();
|
||||
void CreateScene(int width, int height, int samples, bool needsSceneTextures);
|
||||
void CreatePipeline(int width, int height);
|
||||
void CreateBloom(int width, int height);
|
||||
void CreateExposureLevels(int width, int height);
|
||||
void CreateEyeBuffers(int eye);
|
||||
void CreateAmbientOcclusion(int width, int height);
|
||||
GLuint Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data = nullptr);
|
||||
GLuint Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations);
|
||||
GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height);
|
||||
GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height);
|
||||
GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height, int samples);
|
||||
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer);
|
||||
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer);
|
||||
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer);
|
||||
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample);
|
||||
bool CheckFrameBufferCompleteness();
|
||||
void ClearFrameBuffer(bool stencil, bool depth);
|
||||
void DeleteTexture(GLuint &handle);
|
||||
|
@ -94,9 +116,11 @@ private:
|
|||
// Buffers for the scene
|
||||
GLuint mSceneMultisample = 0;
|
||||
GLuint mSceneDepthStencil = 0;
|
||||
GLuint mSceneDepth = 0;
|
||||
GLuint mSceneStencil = 0;
|
||||
GLuint mSceneFog = 0;
|
||||
GLuint mSceneNormal = 0;
|
||||
GLuint mSceneFB = 0;
|
||||
GLuint mSceneDataFB = 0;
|
||||
bool mSceneUsesTextures = false;
|
||||
|
||||
// Effect/HUD buffers
|
||||
GLuint mPipelineTexture[NumPipelineTextures];
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "gl/data/gl_vertexbuffer.h"
|
||||
#include "gl/scene/gl_drawinfo.h"
|
||||
#include "gl/shaders/gl_shader.h"
|
||||
#include "gl/shaders/gl_ambientshader.h"
|
||||
#include "gl/shaders/gl_bloomshader.h"
|
||||
#include "gl/shaders/gl_blurshader.h"
|
||||
#include "gl/shaders/gl_tonemapshader.h"
|
||||
|
@ -118,6 +119,10 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
|
|||
mTonemapPalette = nullptr;
|
||||
mColormapShader = nullptr;
|
||||
mLensShader = nullptr;
|
||||
mLinearDepthShader = nullptr;
|
||||
mDepthBlurShader = nullptr;
|
||||
mSSAOShader = nullptr;
|
||||
mSSAOCombineShader = nullptr;
|
||||
mFXAAShader = nullptr;
|
||||
mFXAALumaShader = nullptr;
|
||||
}
|
||||
|
@ -128,6 +133,10 @@ void gl_FlushModels();
|
|||
void FGLRenderer::Initialize(int width, int height)
|
||||
{
|
||||
mBuffers = new FGLRenderBuffers();
|
||||
mLinearDepthShader = new FLinearDepthShader();
|
||||
mDepthBlurShader = new FDepthBlurShader();
|
||||
mSSAOShader = new FSSAOShader();
|
||||
mSSAOCombineShader = new FSSAOCombineShader();
|
||||
mBloomExtractShader = new FBloomExtractShader();
|
||||
mBloomCombineShader = new FBloomCombineShader();
|
||||
mExposureExtractShader = new FExposureExtractShader();
|
||||
|
@ -196,6 +205,10 @@ FGLRenderer::~FGLRenderer()
|
|||
}
|
||||
if (mBuffers) delete mBuffers;
|
||||
if (mPresentShader) delete mPresentShader;
|
||||
if (mLinearDepthShader) delete mLinearDepthShader;
|
||||
if (mDepthBlurShader) delete mDepthBlurShader;
|
||||
if (mSSAOShader) delete mSSAOShader;
|
||||
if (mSSAOCombineShader) delete mSSAOCombineShader;
|
||||
if (mPresent3dCheckerShader) delete mPresent3dCheckerShader;
|
||||
if (mPresent3dColumnShader) delete mPresent3dColumnShader;
|
||||
if (mPresent3dRowShader) delete mPresent3dRowShader;
|
||||
|
@ -327,7 +340,7 @@ void FGLRenderer::Begin2D()
|
|||
if (mBuffers->Setup(mScreenViewport.width, mScreenViewport.height, mSceneViewport.width, mSceneViewport.height))
|
||||
{
|
||||
if (mDrawingScene2D)
|
||||
mBuffers->BindSceneFB();
|
||||
mBuffers->BindSceneFB(false);
|
||||
else
|
||||
mBuffers->BindCurrentFB();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ class FLightBuffer;
|
|||
class FSamplerManager;
|
||||
class DPSprite;
|
||||
class FGLRenderBuffers;
|
||||
class FLinearDepthShader;
|
||||
class FDepthBlurShader;
|
||||
class FSSAOShader;
|
||||
class FSSAOCombineShader;
|
||||
class FBloomExtractShader;
|
||||
class FBloomCombineShader;
|
||||
class FExposureExtractShader;
|
||||
|
@ -98,6 +102,10 @@ public:
|
|||
int mOldFBID;
|
||||
|
||||
FGLRenderBuffers *mBuffers;
|
||||
FLinearDepthShader *mLinearDepthShader;
|
||||
FSSAOShader *mSSAOShader;
|
||||
FDepthBlurShader *mDepthBlurShader;
|
||||
FSSAOCombineShader *mSSAOCombineShader;
|
||||
FBloomExtractShader *mBloomExtractShader;
|
||||
FBloomCombineShader *mBloomCombineShader;
|
||||
FExposureExtractShader *mExposureExtractShader;
|
||||
|
@ -182,10 +190,12 @@ public:
|
|||
void WriteSavePic (player_t *player, FileWriter *file, int width, int height);
|
||||
void EndDrawScene(sector_t * viewsector);
|
||||
void UpdateCameraExposure();
|
||||
void PostProcessScene();
|
||||
void AmbientOccludeScene();
|
||||
void BloomScene();
|
||||
void TonemapScene();
|
||||
void ColormapScene();
|
||||
void BindTonemapPalette(int texunit);
|
||||
void CreateTonemapPalette();
|
||||
void ClearTonemapPalette();
|
||||
void LensDistortScene();
|
||||
void ApplyFXAA();
|
||||
|
@ -209,6 +219,9 @@ public:
|
|||
DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip);
|
||||
|
||||
int PTM_BestColor (const uint32 *pal_in, int r, int g, int b, int first, int num);
|
||||
|
||||
static float GetZNear() { return 5.f; }
|
||||
static float GetZFar() { return 65536.f; }
|
||||
};
|
||||
|
||||
// Global functions. Make them members of GLRenderer later?
|
||||
|
|
|
@ -105,6 +105,7 @@ void FRenderState::Reset()
|
|||
mViewMatrix.loadIdentity();
|
||||
mModelMatrix.loadIdentity();
|
||||
mTextureMatrix.loadIdentity();
|
||||
mPassType = NORMAL_PASS;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -118,11 +119,11 @@ bool FRenderState::ApplyShader()
|
|||
static const float nulvec[] = { 0.f, 0.f, 0.f, 0.f };
|
||||
if (mSpecialEffect > EFF_NONE)
|
||||
{
|
||||
activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect);
|
||||
activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect, mPassType);
|
||||
}
|
||||
else
|
||||
{
|
||||
activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : 4, mAlphaThreshold >= 0.f);
|
||||
activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : 4, mAlphaThreshold >= 0.f, mPassType);
|
||||
activeShader->Bind();
|
||||
}
|
||||
|
||||
|
@ -347,7 +348,7 @@ void FRenderState::ApplyMatrices()
|
|||
{
|
||||
if (GLRenderer->mShaderManager != NULL)
|
||||
{
|
||||
GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix);
|
||||
GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix, mPassType);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,13 @@ enum EEffect
|
|||
MAX_EFFECTS
|
||||
};
|
||||
|
||||
enum EPassType
|
||||
{
|
||||
NORMAL_PASS,
|
||||
GBUFFER_PASS,
|
||||
MAX_PASS_TYPES
|
||||
};
|
||||
|
||||
class FRenderState
|
||||
{
|
||||
bool mTextureEnabled;
|
||||
|
@ -112,6 +119,9 @@ class FRenderState
|
|||
|
||||
FShader *activeShader;
|
||||
|
||||
EPassType mPassType = NORMAL_PASS;
|
||||
int mNumDrawBuffers = 1;
|
||||
|
||||
bool ApplyShader();
|
||||
|
||||
public:
|
||||
|
@ -472,6 +482,32 @@ public:
|
|||
return mInterpolationFactor;
|
||||
}
|
||||
|
||||
void SetPassType(EPassType passType)
|
||||
{
|
||||
mPassType = passType;
|
||||
}
|
||||
|
||||
EPassType GetPassType()
|
||||
{
|
||||
return mPassType;
|
||||
}
|
||||
|
||||
void EnableDrawBuffers(int count)
|
||||
{
|
||||
count = MIN(count, 3);
|
||||
if (mNumDrawBuffers != count)
|
||||
{
|
||||
static GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
|
||||
glDrawBuffers(count, buffers);
|
||||
mNumDrawBuffers = count;
|
||||
}
|
||||
}
|
||||
|
||||
int GetPassDrawBufferCount()
|
||||
{
|
||||
return mPassType == GBUFFER_PASS ? 3 : 1;
|
||||
}
|
||||
|
||||
// Backwards compatibility crap follows
|
||||
void ApplyFixedFunction();
|
||||
void DrawColormapOverlay();
|
||||
|
|
|
@ -316,6 +316,8 @@ void GLWall::DrawDecal(DBaseDecal *decal)
|
|||
gl_RenderState.SetFog(0,-1);
|
||||
}
|
||||
|
||||
gl_RenderState.SetNormal(glseg.Normal());
|
||||
|
||||
FQuadDrawer qd;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
|
|
|
@ -423,14 +423,16 @@ void GLPortal::End(bool usestencil)
|
|||
glDepthFunc(GL_LEQUAL);
|
||||
glDepthRange(0, 1);
|
||||
{
|
||||
ScopedColorMask colorMask(0, 0, 0, 0);
|
||||
// glColorMask(0,0,0,0); // no graphics
|
||||
ScopedColorMask colorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color
|
||||
gl_RenderState.SetEffect(EFF_STENCIL);
|
||||
gl_RenderState.EnableTexture(false);
|
||||
gl_RenderState.BlendFunc(GL_ONE, GL_ZERO);
|
||||
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
||||
gl_RenderState.Apply();
|
||||
DrawPortalStencil();
|
||||
gl_RenderState.SetEffect(EFF_NONE);
|
||||
gl_RenderState.EnableTexture(true);
|
||||
} // glColorMask(1, 1, 1, 1);
|
||||
}
|
||||
glDepthFunc(GL_LESS);
|
||||
}
|
||||
PortalAll.Unclock();
|
||||
|
|
|
@ -158,7 +158,11 @@ void FGLRenderer::Set3DViewport(bool mainview)
|
|||
{
|
||||
if (mainview && mBuffers->Setup(mScreenViewport.width, mScreenViewport.height, mSceneViewport.width, mSceneViewport.height))
|
||||
{
|
||||
mBuffers->BindSceneFB();
|
||||
bool useSSAO = (gl_ssao != 0);
|
||||
mBuffers->BindSceneFB(useSSAO);
|
||||
gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
gl_RenderState.Apply();
|
||||
}
|
||||
|
||||
// Always clear all buffers with scissor test disabled.
|
||||
|
@ -209,7 +213,7 @@ void FGLRenderer::SetProjection(float fov, float ratio, float fovratio)
|
|||
{
|
||||
|
||||
float fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovratio));
|
||||
gl_RenderState.mProjectionMatrix.perspective(fovy, ratio, 5.f, 65536.f);
|
||||
gl_RenderState.mProjectionMatrix.perspective(fovy, ratio, GetZNear(), GetZFar());
|
||||
}
|
||||
|
||||
// raw matrix input from stereo 3d modes
|
||||
|
@ -472,6 +476,23 @@ void FGLRenderer::RenderTranslucent()
|
|||
void FGLRenderer::DrawScene(int drawmode)
|
||||
{
|
||||
static int recursion=0;
|
||||
static int ssao_portals_available = 0;
|
||||
|
||||
bool applySSAO = false;
|
||||
if (drawmode == DM_MAINVIEW)
|
||||
{
|
||||
ssao_portals_available = gl_ssao_portals;
|
||||
applySSAO = true;
|
||||
}
|
||||
else if (drawmode == DM_OFFSCREEN)
|
||||
{
|
||||
ssao_portals_available = 0;
|
||||
}
|
||||
else if (ssao_portals_available > 0)
|
||||
{
|
||||
applySSAO = true;
|
||||
ssao_portals_available--;
|
||||
}
|
||||
|
||||
if (camera != nullptr)
|
||||
{
|
||||
|
@ -491,6 +512,16 @@ void FGLRenderer::DrawScene(int drawmode)
|
|||
|
||||
RenderScene(recursion);
|
||||
|
||||
if (applySSAO && gl_RenderState.GetPassType() == GBUFFER_PASS)
|
||||
{
|
||||
gl_RenderState.EnableDrawBuffers(1);
|
||||
AmbientOccludeScene();
|
||||
mBuffers->BindSceneFB(true);
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
gl_RenderState.Apply();
|
||||
gl_RenderState.ApplyMatrices();
|
||||
}
|
||||
|
||||
// Handle all portals after rendering the opaque objects but before
|
||||
// doing all translucent stuff
|
||||
recursion++;
|
||||
|
@ -830,13 +861,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
|
|||
if (mainview && toscreen) EndDrawScene(lviewsector); // do not call this for camera textures.
|
||||
if (mainview && FGLRenderBuffers::IsEnabled())
|
||||
{
|
||||
mBuffers->BlitSceneToTexture();
|
||||
UpdateCameraExposure();
|
||||
BloomScene();
|
||||
TonemapScene();
|
||||
ColormapScene();
|
||||
LensDistortScene();
|
||||
ApplyFXAA();
|
||||
PostProcessScene();
|
||||
|
||||
// This should be done after postprocessing, not before.
|
||||
mBuffers->BindCurrentFB();
|
||||
|
|
|
@ -228,6 +228,7 @@ void GLWall::RenderFogBoundary()
|
|||
{
|
||||
int rel = rellight + getExtraLight();
|
||||
gl_SetFog(lightlevel, rel, &Colormap, false);
|
||||
gl_RenderState.EnableDrawBuffers(1);
|
||||
gl_RenderState.SetEffect(EFF_FOGBOUNDARY);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
|
@ -236,6 +237,7 @@ void GLWall::RenderFogBoundary()
|
|||
glPolygonOffset(0.0f, 0.0f);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
gl_RenderState.SetEffect(EFF_NONE);
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
160
src/gl/shaders/gl_ambientshader.cpp
Normal file
160
src/gl/shaders/gl_ambientshader.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016 Magnus Norddahl
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "gl/system/gl_system.h"
|
||||
#include "files.h"
|
||||
#include "m_swap.h"
|
||||
#include "v_video.h"
|
||||
#include "gl/gl_functions.h"
|
||||
#include "vectors.h"
|
||||
#include "gl/system/gl_interface.h"
|
||||
#include "gl/system/gl_framebuffer.h"
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/shaders/gl_ambientshader.h"
|
||||
|
||||
void FLinearDepthShader::Bind()
|
||||
{
|
||||
bool multisample = (gl_multisample > 1);
|
||||
if (mMultisample != multisample)
|
||||
mShader.reset();
|
||||
|
||||
if (!mShader)
|
||||
{
|
||||
mShader = std::make_unique<FShaderProgram>();
|
||||
mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", multisample ? "#define MULTISAMPLE\n" : "", 330);
|
||||
mShader->SetFragDataLocation(0, "FragColor");
|
||||
mShader->Link("shaders/glsl/lineardepth");
|
||||
mShader->SetAttribLocation(0, "PositionInProjection");
|
||||
DepthTexture.Init(*mShader, "DepthTexture");
|
||||
ColorTexture.Init(*mShader, "ColorTexture");
|
||||
SampleIndex.Init(*mShader, "SampleIndex");
|
||||
LinearizeDepthA.Init(*mShader, "LinearizeDepthA");
|
||||
LinearizeDepthB.Init(*mShader, "LinearizeDepthB");
|
||||
InverseDepthRangeA.Init(*mShader, "InverseDepthRangeA");
|
||||
InverseDepthRangeB.Init(*mShader, "InverseDepthRangeB");
|
||||
Scale.Init(*mShader, "Scale");
|
||||
Offset.Init(*mShader, "Offset");
|
||||
mMultisample = multisample;
|
||||
}
|
||||
mShader->Bind();
|
||||
}
|
||||
|
||||
void FSSAOShader::Bind()
|
||||
{
|
||||
bool multisample = (gl_multisample > 1);
|
||||
if (mCurrentQuality != gl_ssao || mMultisample != multisample)
|
||||
mShader.reset();
|
||||
|
||||
if (!mShader)
|
||||
{
|
||||
mShader = std::make_unique<FShaderProgram>();
|
||||
mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", GetDefines(gl_ssao, multisample), 330);
|
||||
mShader->SetFragDataLocation(0, "FragColor");
|
||||
mShader->Link("shaders/glsl/ssao");
|
||||
mShader->SetAttribLocation(0, "PositionInProjection");
|
||||
DepthTexture.Init(*mShader, "DepthTexture");
|
||||
NormalTexture.Init(*mShader, "NormalTexture");
|
||||
RandomTexture.Init(*mShader, "RandomTexture");
|
||||
UVToViewA.Init(*mShader, "UVToViewA");
|
||||
UVToViewB.Init(*mShader, "UVToViewB");
|
||||
InvFullResolution.Init(*mShader, "InvFullResolution");
|
||||
NDotVBias.Init(*mShader, "NDotVBias");
|
||||
NegInvR2.Init(*mShader, "NegInvR2");
|
||||
RadiusToScreen.Init(*mShader, "RadiusToScreen");
|
||||
AOMultiplier.Init(*mShader, "AOMultiplier");
|
||||
AOStrength.Init(*mShader, "AOStrength");
|
||||
Scale.Init(*mShader, "Scale");
|
||||
Offset.Init(*mShader, "Offset");
|
||||
SampleIndex.Init(*mShader, "SampleIndex");
|
||||
mMultisample = multisample;
|
||||
}
|
||||
mShader->Bind();
|
||||
}
|
||||
|
||||
FString FSSAOShader::GetDefines(int mode, bool multisample)
|
||||
{
|
||||
// Must match quality values in FGLRenderBuffers::CreateAmbientOcclusion
|
||||
int numDirections, numSteps;
|
||||
switch (gl_ssao)
|
||||
{
|
||||
default:
|
||||
case LowQuality: numDirections = 2; numSteps = 4; break;
|
||||
case MediumQuality: numDirections = 4; numSteps = 4; break;
|
||||
case HighQuality: numDirections = 8; numSteps = 4; break;
|
||||
}
|
||||
|
||||
FString defines;
|
||||
defines.Format(R"(
|
||||
#define USE_RANDOM_TEXTURE
|
||||
#define RANDOM_TEXTURE_WIDTH 4.0
|
||||
#define NUM_DIRECTIONS %d.0
|
||||
#define NUM_STEPS %d.0
|
||||
)", numDirections, numSteps);
|
||||
|
||||
if (multisample)
|
||||
defines += "\n#define MULTISAMPLE\n";
|
||||
return defines;
|
||||
}
|
||||
|
||||
void FDepthBlurShader::Bind(bool vertical)
|
||||
{
|
||||
auto &shader = mShader[vertical];
|
||||
if (!shader)
|
||||
{
|
||||
shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
shader.Compile(FShaderProgram::Fragment, "shaders/glsl/depthblur.fp", vertical ? "#define BLUR_VERTICAL\n" : "#define BLUR_HORIZONTAL\n", 330);
|
||||
shader.SetFragDataLocation(0, "FragColor");
|
||||
shader.Link("shaders/glsl/depthblur");
|
||||
shader.SetAttribLocation(0, "PositionInProjection");
|
||||
AODepthTexture[vertical].Init(shader, "AODepthTexture");
|
||||
BlurSharpness[vertical].Init(shader, "BlurSharpness");
|
||||
InvFullResolution[vertical].Init(shader, "InvFullResolution");
|
||||
PowExponent[vertical].Init(shader, "PowExponent");
|
||||
}
|
||||
shader.Bind();
|
||||
}
|
||||
|
||||
void FSSAOCombineShader::Bind()
|
||||
{
|
||||
bool multisample = (gl_multisample > 1);
|
||||
if (mMultisample != multisample)
|
||||
mShader.reset();
|
||||
|
||||
if (!mShader)
|
||||
{
|
||||
mShader = std::make_unique<FShaderProgram>();
|
||||
mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", multisample ? "#define MULTISAMPLE\n" : "", 330);
|
||||
mShader->SetFragDataLocation(0, "FragColor");
|
||||
mShader->Link("shaders/glsl/ssaocombine");
|
||||
mShader->SetAttribLocation(0, "PositionInProjection");
|
||||
AODepthTexture.Init(*mShader, "AODepthTexture");
|
||||
SceneFogTexture.Init(*mShader, "SceneFogTexture");
|
||||
SampleCount.Init(*mShader, "SampleCount");
|
||||
Scale.Init(*mShader, "Scale");
|
||||
Offset.Init(*mShader, "Offset");
|
||||
mMultisample = multisample;
|
||||
}
|
||||
mShader->Bind();
|
||||
}
|
93
src/gl/shaders/gl_ambientshader.h
Normal file
93
src/gl/shaders/gl_ambientshader.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
#ifndef __GL_AMBIENTSHADER_H
|
||||
#define __GL_AMBIENTSHADER_H
|
||||
|
||||
#include "gl_shaderprogram.h"
|
||||
|
||||
class FLinearDepthShader
|
||||
{
|
||||
public:
|
||||
void Bind();
|
||||
|
||||
FBufferedUniformSampler DepthTexture;
|
||||
FBufferedUniformSampler ColorTexture;
|
||||
FBufferedUniform1i SampleIndex;
|
||||
FBufferedUniform1f LinearizeDepthA;
|
||||
FBufferedUniform1f LinearizeDepthB;
|
||||
FBufferedUniform1f InverseDepthRangeA;
|
||||
FBufferedUniform1f InverseDepthRangeB;
|
||||
FBufferedUniform2f Scale;
|
||||
FBufferedUniform2f Offset;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FShaderProgram> mShader;
|
||||
bool mMultisample = false;
|
||||
};
|
||||
|
||||
class FSSAOShader
|
||||
{
|
||||
public:
|
||||
void Bind();
|
||||
|
||||
FBufferedUniformSampler DepthTexture;
|
||||
FBufferedUniformSampler NormalTexture;
|
||||
FBufferedUniformSampler RandomTexture;
|
||||
FBufferedUniform2f UVToViewA;
|
||||
FBufferedUniform2f UVToViewB;
|
||||
FBufferedUniform2f InvFullResolution;
|
||||
FBufferedUniform1f NDotVBias;
|
||||
FBufferedUniform1f NegInvR2;
|
||||
FBufferedUniform1f RadiusToScreen;
|
||||
FBufferedUniform1f AOMultiplier;
|
||||
FBufferedUniform1f AOStrength;
|
||||
FBufferedUniform2f Scale;
|
||||
FBufferedUniform2f Offset;
|
||||
FBufferedUniform1i SampleIndex;
|
||||
|
||||
private:
|
||||
enum Quality
|
||||
{
|
||||
Off,
|
||||
LowQuality,
|
||||
MediumQuality,
|
||||
HighQuality,
|
||||
NumQualityModes
|
||||
};
|
||||
|
||||
FString GetDefines(int mode, bool multisample);
|
||||
|
||||
std::unique_ptr<FShaderProgram> mShader;
|
||||
Quality mCurrentQuality = Off;
|
||||
bool mMultisample = false;
|
||||
};
|
||||
|
||||
class FDepthBlurShader
|
||||
{
|
||||
public:
|
||||
void Bind(bool vertical);
|
||||
|
||||
FBufferedUniformSampler AODepthTexture[2];
|
||||
FBufferedUniform1f BlurSharpness[2];
|
||||
FBufferedUniform2f InvFullResolution[2];
|
||||
FBufferedUniform1f PowExponent[2];
|
||||
|
||||
private:
|
||||
FShaderProgram mShader[2];
|
||||
};
|
||||
|
||||
class FSSAOCombineShader
|
||||
{
|
||||
public:
|
||||
void Bind();
|
||||
|
||||
FBufferedUniformSampler AODepthTexture;
|
||||
FBufferedUniformSampler SceneFogTexture;
|
||||
FBufferedUniform1i SampleCount;
|
||||
FBufferedUniform2f Scale;
|
||||
FBufferedUniform2f Offset;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FShaderProgram> mShader;
|
||||
bool mMultisample = false;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -181,6 +181,10 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
|
|||
glBindAttribLocation(hShader, VATTR_VERTEX2, "aVertex2");
|
||||
glBindAttribLocation(hShader, VATTR_NORMAL, "aNormal");
|
||||
|
||||
glBindFragDataLocation(hShader, 0, "FragColor");
|
||||
glBindFragDataLocation(hShader, 1, "FragFog");
|
||||
glBindFragDataLocation(hShader, 2, "FragNormal");
|
||||
|
||||
glLinkProgram(hShader);
|
||||
|
||||
glGetShaderInfoLog(hVertProg, 10000, NULL, buffer);
|
||||
|
@ -300,12 +304,13 @@ bool FShader::Bind()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader *FShaderManager::Compile (const char *ShaderName, const char *ShaderPath, bool usediscard)
|
||||
FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, bool usediscard, EPassType passType)
|
||||
{
|
||||
FString defines;
|
||||
// this can't be in the shader code due to ATI strangeness.
|
||||
if (gl.MaxLights() == 128) defines += "#define MAXLIGHTS128\n";
|
||||
if (!usediscard) defines += "#define NO_ALPHATEST\n";
|
||||
if (passType == GBUFFER_PASS) defines += "#define GBUFFER_PASS\n";
|
||||
|
||||
FShader *shader = NULL;
|
||||
try
|
||||
|
@ -388,27 +393,75 @@ static const FEffectShader effectshaders[]=
|
|||
{ "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" },
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderManager::FShaderManager()
|
||||
{
|
||||
if (!gl.legacyMode) CompileShaders();
|
||||
if (!gl.legacyMode)
|
||||
{
|
||||
for (int passType = 0; passType < MAX_PASS_TYPES; passType++)
|
||||
mPassShaders.Push(new FShaderCollection((EPassType)passType));
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderManager::~FShaderManager()
|
||||
{
|
||||
if (!gl.legacyMode) Clean();
|
||||
if (!gl.legacyMode)
|
||||
{
|
||||
glUseProgram(0);
|
||||
mActiveShader = NULL;
|
||||
|
||||
for (auto collection : mPassShaders)
|
||||
delete collection;
|
||||
}
|
||||
}
|
||||
|
||||
void FShaderManager::SetActiveShader(FShader *sh)
|
||||
{
|
||||
if (mActiveShader != sh)
|
||||
{
|
||||
glUseProgram(sh!= NULL? sh->GetHandle() : 0);
|
||||
mActiveShader = sh;
|
||||
}
|
||||
}
|
||||
|
||||
FShader *FShaderManager::BindEffect(int effect, EPassType passType)
|
||||
{
|
||||
if (passType < mPassShaders.Size())
|
||||
return mPassShaders[passType]->BindEffect(effect);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType)
|
||||
{
|
||||
if (passType < mPassShaders.Size())
|
||||
return mPassShaders[passType]->Get(eff, alphateston);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType)
|
||||
{
|
||||
if (gl.legacyMode)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf(proj->get());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf(view->get());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (passType < mPassShaders.Size())
|
||||
mPassShaders[passType]->ApplyMatrices(proj, view);
|
||||
|
||||
if (mActiveShader)
|
||||
mActiveShader->Bind();
|
||||
}
|
||||
}
|
||||
|
||||
void FShaderManager::ResetFixedColormap()
|
||||
{
|
||||
for (auto &collection : mPassShaders)
|
||||
collection->ResetFixedColormap();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -417,10 +470,30 @@ FShaderManager::~FShaderManager()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderManager::CompileShaders()
|
||||
FShaderCollection::FShaderCollection(EPassType passType)
|
||||
{
|
||||
mActiveShader = NULL;
|
||||
CompileShaders(passType);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderCollection::~FShaderCollection()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderCollection::CompileShaders(EPassType passType)
|
||||
{
|
||||
mTextureEffects.Clear();
|
||||
mTextureEffectsNAT.Clear();
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
|
@ -430,11 +503,11 @@ void FShaderManager::CompileShaders()
|
|||
|
||||
for(int i=0;defaultshaders[i].ShaderName != NULL;i++)
|
||||
{
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true);
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true, passType);
|
||||
mTextureEffects.Push(shc);
|
||||
if (i <= 3)
|
||||
{
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false);
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false, passType);
|
||||
mTextureEffectsNAT.Push(shc);
|
||||
}
|
||||
}
|
||||
|
@ -444,7 +517,7 @@ void FShaderManager::CompileShaders()
|
|||
FString name = ExtractFileBase(usershaders[i]);
|
||||
FName sfn = name;
|
||||
|
||||
FShader *shc = Compile(sfn, usershaders[i], true);
|
||||
FShader *shc = Compile(sfn, usershaders[i], true, passType);
|
||||
mTextureEffects.Push(shc);
|
||||
}
|
||||
|
||||
|
@ -466,11 +539,8 @@ void FShaderManager::CompileShaders()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderManager::Clean()
|
||||
void FShaderCollection::Clean()
|
||||
{
|
||||
glUseProgram(0);
|
||||
mActiveShader = NULL;
|
||||
|
||||
for (unsigned int i = 0; i < mTextureEffectsNAT.Size(); i++)
|
||||
{
|
||||
if (mTextureEffectsNAT[i] != NULL) delete mTextureEffectsNAT[i];
|
||||
|
@ -494,7 +564,7 @@ void FShaderManager::Clean()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int FShaderManager::Find(const char * shn)
|
||||
int FShaderCollection::Find(const char * shn)
|
||||
{
|
||||
FName sfn = shn;
|
||||
|
||||
|
@ -508,21 +578,6 @@ int FShaderManager::Find(const char * shn)
|
|||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderManager::SetActiveShader(FShader *sh)
|
||||
{
|
||||
if (mActiveShader != sh)
|
||||
{
|
||||
glUseProgram(sh!= NULL? sh->GetHandle() : 0);
|
||||
mActiveShader = sh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -530,7 +585,7 @@ void FShaderManager::SetActiveShader(FShader *sh)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader *FShaderManager::BindEffect(int effect)
|
||||
FShader *FShaderCollection::BindEffect(int effect)
|
||||
{
|
||||
if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL)
|
||||
{
|
||||
|
@ -548,39 +603,28 @@ FShader *FShaderManager::BindEffect(int effect)
|
|||
//==========================================================================
|
||||
EXTERN_CVAR(Int, gl_fuzztype)
|
||||
|
||||
void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
|
||||
void FShaderCollection::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
|
||||
{
|
||||
if (gl.legacyMode)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf(proj->get());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf(view->get());
|
||||
}
|
||||
else
|
||||
{
|
||||
VSMatrix norm;
|
||||
norm.computeNormalMatrix(*view);
|
||||
VSMatrix norm;
|
||||
norm.computeNormalMatrix(*view);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
|
||||
mTextureEffectsNAT[i]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
mTextureEffects[4]->ApplyMatrices(proj, view, &norm);
|
||||
if (gl_fuzztype != 0)
|
||||
{
|
||||
mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
for (unsigned i = 12; i < mTextureEffects.Size(); i++)
|
||||
{
|
||||
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
mEffectShaders[i]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
if (mActiveShader != NULL) mActiveShader->Bind();
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
|
||||
mTextureEffectsNAT[i]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
mTextureEffects[4]->ApplyMatrices(proj, view, &norm);
|
||||
if (gl_fuzztype != 0)
|
||||
{
|
||||
mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
for (unsigned i = 12; i < mTextureEffects.Size(); i++)
|
||||
{
|
||||
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
mEffectShaders[i]->ApplyMatrices(proj, view, &norm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ enum
|
|||
VATTR_NORMAL = 4
|
||||
};
|
||||
|
||||
class FShaderCollection;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -248,7 +249,7 @@ public:
|
|||
|
||||
class FShader
|
||||
{
|
||||
friend class FShaderManager;
|
||||
friend class FShaderCollection;
|
||||
friend class FRenderState;
|
||||
|
||||
unsigned int hShader;
|
||||
|
@ -324,7 +325,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// The global shader manager
|
||||
|
@ -332,26 +332,40 @@ public:
|
|||
//==========================================================================
|
||||
class FShaderManager
|
||||
{
|
||||
TArray<FShader*> mTextureEffects;
|
||||
TArray<FShader*> mTextureEffectsNAT;
|
||||
FShader *mActiveShader;
|
||||
FShader *mEffectShaders[MAX_EFFECTS];
|
||||
|
||||
void Clean();
|
||||
void CompileShaders();
|
||||
|
||||
public:
|
||||
FShaderManager();
|
||||
~FShaderManager();
|
||||
FShader *Compile(const char *ShaderName, const char *ShaderPath, bool usediscard);
|
||||
|
||||
void SetActiveShader(FShader *sh);
|
||||
FShader *GetActiveShader() const { return mActiveShader; }
|
||||
|
||||
FShader *BindEffect(int effect, EPassType passType);
|
||||
FShader *Get(unsigned int eff, bool alphateston, EPassType passType);
|
||||
void ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType);
|
||||
|
||||
void ResetFixedColormap();
|
||||
|
||||
private:
|
||||
FShader *mActiveShader = nullptr;
|
||||
TArray<FShaderCollection*> mPassShaders;
|
||||
};
|
||||
|
||||
class FShaderCollection
|
||||
{
|
||||
TArray<FShader*> mTextureEffects;
|
||||
TArray<FShader*> mTextureEffectsNAT;
|
||||
FShader *mEffectShaders[MAX_EFFECTS];
|
||||
|
||||
void Clean();
|
||||
void CompileShaders(EPassType passType);
|
||||
|
||||
public:
|
||||
FShaderCollection(EPassType passType);
|
||||
~FShaderCollection();
|
||||
FShader *Compile(const char *ShaderName, const char *ShaderPath, bool usediscard, EPassType passType);
|
||||
int Find(const char *mame);
|
||||
FShader *BindEffect(int effect);
|
||||
void SetActiveShader(FShader *sh);
|
||||
void ApplyMatrices(VSMatrix *proj, VSMatrix *view);
|
||||
FShader *GetActiveShader() const
|
||||
{
|
||||
return mActiveShader;
|
||||
}
|
||||
|
||||
void ResetFixedColormap()
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@ VSMatrix EyePose::GetProjection(float fov, float aspectRatio, float fovRatio) co
|
|||
|
||||
// Lifted from gl_scene.cpp FGLRenderer::SetProjection()
|
||||
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
|
||||
result.perspective(fovy, aspectRatio, 5.f, 65536.f);
|
||||
result.perspective(fovy, aspectRatio, FGLRenderer::GetZNear(), FGLRenderer::GetZFar());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,10 @@ public:
|
|||
gl_RenderState.GetColorMask(saved[0], saved[1], saved[2], saved[3]);
|
||||
gl_RenderState.SetColorMask(r, g, b, a);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
gl_RenderState.EnableDrawBuffers(1);
|
||||
}
|
||||
~ScopedColorMask() {
|
||||
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
|
||||
gl_RenderState.SetColorMask(saved[0], saved[1], saved[2], saved[3]);
|
||||
gl_RenderState.ApplyColorMask();
|
||||
}
|
||||
|
|
|
@ -50,6 +50,13 @@ EXTERN_CVAR(Bool, gl_lens)
|
|||
EXTERN_CVAR(Float, gl_lens_k)
|
||||
EXTERN_CVAR(Float, gl_lens_kcube)
|
||||
EXTERN_CVAR(Float, gl_lens_chromatic)
|
||||
EXTERN_CVAR(Int, gl_ssao)
|
||||
EXTERN_CVAR(Int, gl_ssao_portals)
|
||||
EXTERN_CVAR(Float, gl_ssao_strength)
|
||||
EXTERN_CVAR(Int, gl_ssao_debug)
|
||||
EXTERN_CVAR(Float, gl_ssao_bias)
|
||||
EXTERN_CVAR(Float, gl_ssao_radius)
|
||||
EXTERN_CVAR(Float, gl_ssao_blur_amount)
|
||||
|
||||
EXTERN_CVAR(Int, gl_debug_level)
|
||||
EXTERN_CVAR(Bool, gl_debug_breakpoint)
|
||||
|
|
|
@ -374,6 +374,11 @@ unsigned int FHardwareTexture::Bind(int texunit, int translation, bool needmipma
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned int FHardwareTexture::GetTextureHandle(int translation)
|
||||
{
|
||||
TranslatedTexture *pTex = GetTexID(translation);
|
||||
return pTex->glTexID;
|
||||
}
|
||||
|
||||
void FHardwareTexture::Unbind(int texunit)
|
||||
{
|
||||
|
|
|
@ -83,6 +83,7 @@ public:
|
|||
|
||||
unsigned int Bind(int texunit, int translation, bool needmipmap);
|
||||
unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const FString &name);
|
||||
unsigned int GetTextureHandle(int translation);
|
||||
|
||||
void Clean(bool all);
|
||||
void CleanUnused(SpriteHits &usedtranslations);
|
||||
|
|
|
@ -2171,6 +2171,9 @@ NETMNU_TICBALANCE = "Latency balancing";
|
|||
// Option Values
|
||||
OPTVAL_OFF = "Off";
|
||||
OPTVAL_ON = "On";
|
||||
OPTVAL_LOW = "Low";
|
||||
OPTVAL_MEDIUM = "Medium";
|
||||
OPTVAL_HIGH = "High";
|
||||
OPTVAL_MALE = "Male";
|
||||
OPTVAL_FEMALE = "Female";
|
||||
OPTVAL_OTHER = "Other";
|
||||
|
@ -2640,6 +2643,8 @@ GLPREFMNU_MULTISAMPLE = "Multisample";
|
|||
GLPREFMNU_TONEMAP = "Tonemap Mode";
|
||||
GLPREFMNU_BLOOM = "Bloom effect";
|
||||
GLPREFMNU_LENS = "Lens distortion effect";
|
||||
GLPREFMNU_SSAO = "Ambient occlusion quality";
|
||||
GLPREFMNU_SSAO_PORTALS = "Portals with AO";
|
||||
GLPREFMNU_FXAA = "FXAA Quality";
|
||||
|
||||
// Option Values
|
||||
|
|
|
@ -42,6 +42,14 @@ OptionValue "TonemapModes"
|
|||
5, "$OPTVAL_PALETTE"
|
||||
}
|
||||
|
||||
OptionValue "SSAOModes"
|
||||
{
|
||||
0, "$OPTVAL_OFF"
|
||||
1, "$OPTVAL_LOW"
|
||||
2, "$OPTVAL_MEDIUM"
|
||||
3, "$OPTVAL_HIGH"
|
||||
}
|
||||
|
||||
OptionValue "FXAAQuality"
|
||||
{
|
||||
0, "$OPTVAL_OFF"
|
||||
|
@ -238,5 +246,7 @@ OptionMenu "GLPrefOptions"
|
|||
Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes"
|
||||
Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff"
|
||||
Option "$GLPREFMNU_LENS", gl_lens, "OnOff"
|
||||
Option "$GLPREFMNU_SSAO", gl_ssao, "SSAOModes"
|
||||
Slider "$GLPREFMNU_SSAO_PORTALS", gl_ssao_portals, 0.0, 4.0, 1.0, 0
|
||||
Option "$GLPREFMNU_FXAA", gl_fxaa, "FXAAQuality"
|
||||
}
|
||||
|
|
69
wadsrc/static/shaders/glsl/depthblur.fp
Normal file
69
wadsrc/static/shaders/glsl/depthblur.fp
Normal file
|
@ -0,0 +1,69 @@
|
|||
|
||||
in vec2 TexCoord;
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D AODepthTexture;
|
||||
uniform float BlurSharpness;
|
||||
uniform vec2 InvFullResolution;
|
||||
uniform float PowExponent;
|
||||
|
||||
#define KERNEL_RADIUS 3.0
|
||||
|
||||
float CrossBilateralWeight(float r, float sampleDepth, float centerDepth)
|
||||
{
|
||||
const float blurSigma = KERNEL_RADIUS * 0.5;
|
||||
const float blurFalloff = 1.0 / (2.0 * blurSigma * blurSigma);
|
||||
|
||||
float deltaZ = (sampleDepth - centerDepth) * BlurSharpness;
|
||||
|
||||
return exp2(-r * r * blurFalloff - deltaZ * deltaZ);
|
||||
}
|
||||
|
||||
void ProcessSample(float ao, float z, float r, float centerDepth, inout float totalAO, inout float totalW)
|
||||
{
|
||||
float w = CrossBilateralWeight(r, z, centerDepth);
|
||||
totalAO += w * ao;
|
||||
totalW += w;
|
||||
}
|
||||
|
||||
void ProcessRadius(vec2 deltaUV, float centerDepth, inout float totalAO, inout float totalW)
|
||||
{
|
||||
for (float r = 1; r <= KERNEL_RADIUS; r += 1.0)
|
||||
{
|
||||
vec2 uv = r * deltaUV + TexCoord;
|
||||
vec2 aoZ = texture(AODepthTexture, uv).xy;
|
||||
ProcessSample(aoZ.x, aoZ.y, r, centerDepth, totalAO, totalW);
|
||||
}
|
||||
}
|
||||
|
||||
vec2 ComputeBlur(vec2 deltaUV)
|
||||
{
|
||||
vec2 aoZ = texture(AODepthTexture, TexCoord).xy;
|
||||
|
||||
float totalAO = aoZ.x;
|
||||
float totalW = 1.0;
|
||||
|
||||
ProcessRadius(deltaUV, aoZ.y, totalAO, totalW);
|
||||
ProcessRadius(-deltaUV, aoZ.y, totalAO, totalW);
|
||||
|
||||
return vec2(totalAO / totalW, aoZ.y);
|
||||
}
|
||||
|
||||
vec2 BlurX()
|
||||
{
|
||||
return ComputeBlur(vec2(InvFullResolution.x, 0.0));
|
||||
}
|
||||
|
||||
float BlurY()
|
||||
{
|
||||
return pow(clamp(ComputeBlur(vec2(0.0, InvFullResolution.y)).x, 0.0, 1.0), PowExponent);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(BLUR_HORIZONTAL)
|
||||
FragColor = vec4(BlurX(), 0.0, 1.0);
|
||||
#else
|
||||
FragColor = vec4(BlurY(), 0.0, 0.0, 1.0);
|
||||
#endif
|
||||
}
|
46
wadsrc/static/shaders/glsl/lineardepth.fp
Normal file
46
wadsrc/static/shaders/glsl/lineardepth.fp
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
in vec2 TexCoord;
|
||||
out vec4 FragColor;
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
uniform sampler2DMS DepthTexture;
|
||||
uniform sampler2DMS ColorTexture;
|
||||
uniform int SampleIndex;
|
||||
#else
|
||||
uniform sampler2D DepthTexture;
|
||||
uniform sampler2D ColorTexture;
|
||||
#endif
|
||||
|
||||
uniform float LinearizeDepthA;
|
||||
uniform float LinearizeDepthB;
|
||||
uniform float InverseDepthRangeA;
|
||||
uniform float InverseDepthRangeB;
|
||||
uniform vec2 Scale;
|
||||
uniform vec2 Offset;
|
||||
|
||||
float normalizeDepth(float depth)
|
||||
{
|
||||
float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0);
|
||||
return 1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = Offset + TexCoord * Scale;
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
ivec2 texSize = textureSize(DepthTexture);
|
||||
#else
|
||||
ivec2 texSize = textureSize(DepthTexture, 0);
|
||||
#endif
|
||||
|
||||
ivec2 ipos = ivec2(max(uv * vec2(texSize), vec2(0.0)));
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
float depth = normalizeDepth(texelFetch(ColorTexture, ipos, SampleIndex).a != 0.0 ? texelFetch(DepthTexture, ipos, SampleIndex).x : 1.0);
|
||||
#else
|
||||
float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0);
|
||||
#endif
|
||||
|
||||
FragColor = vec4(depth, 0.0, 0.0, 1.0);
|
||||
}
|
|
@ -7,6 +7,10 @@ in vec4 vTexCoord;
|
|||
in vec4 vColor;
|
||||
|
||||
out vec4 FragColor;
|
||||
#ifdef GBUFFER_PASS
|
||||
out vec4 FragFog;
|
||||
out vec4 FragNormal;
|
||||
#endif
|
||||
|
||||
#ifdef SHADER_STORAGE_LIGHTS
|
||||
layout(std430, binding = 1) buffer LightBufferSSO
|
||||
|
@ -266,6 +270,32 @@ vec4 applyFog(vec4 frag, float fogfactor)
|
|||
return vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// The color of the fragment if it is fully occluded by ambient lighting
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
vec3 AmbientOcclusionColor()
|
||||
{
|
||||
float fogdist;
|
||||
float fogfactor;
|
||||
|
||||
//
|
||||
// calculate fog factor
|
||||
//
|
||||
if (uFogEnabled == -1)
|
||||
{
|
||||
fogdist = pixelpos.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz));
|
||||
}
|
||||
fogfactor = exp2 (uFogDensity * fogdist);
|
||||
|
||||
return mix(uFogColor.rgb, vec3(0.0), fogfactor);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -381,5 +411,9 @@ void main()
|
|||
}
|
||||
}
|
||||
FragColor = frag;
|
||||
#ifdef GBUFFER_PASS
|
||||
FragFog = vec4(AmbientOcclusionColor(), 1.0);
|
||||
FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
138
wadsrc/static/shaders/glsl/ssao.fp
Normal file
138
wadsrc/static/shaders/glsl/ssao.fp
Normal file
|
@ -0,0 +1,138 @@
|
|||
|
||||
in vec2 TexCoord;
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform vec2 UVToViewA;
|
||||
uniform vec2 UVToViewB;
|
||||
uniform vec2 InvFullResolution;
|
||||
|
||||
uniform float NDotVBias;
|
||||
uniform float NegInvR2;
|
||||
uniform float RadiusToScreen;
|
||||
uniform float AOMultiplier;
|
||||
|
||||
uniform float AOStrength;
|
||||
|
||||
uniform vec2 Scale;
|
||||
uniform vec2 Offset;
|
||||
|
||||
uniform sampler2D DepthTexture;
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
uniform sampler2DMS NormalTexture;
|
||||
uniform int SampleIndex;
|
||||
#else
|
||||
uniform sampler2D NormalTexture;
|
||||
#endif
|
||||
|
||||
#if defined(USE_RANDOM_TEXTURE)
|
||||
uniform sampler2D RandomTexture;
|
||||
#endif
|
||||
|
||||
#define PI 3.14159265358979323846
|
||||
|
||||
// Calculate eye space position for the specified texture coordinate
|
||||
vec3 FetchViewPos(vec2 uv)
|
||||
{
|
||||
float z = texture(DepthTexture, uv).x;
|
||||
return vec3((UVToViewA * uv + UVToViewB) * z, z);
|
||||
}
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
vec3 SampleNormal(vec2 uv)
|
||||
{
|
||||
ivec2 texSize = textureSize(NormalTexture);
|
||||
ivec2 ipos = ivec2(uv * vec2(texSize));
|
||||
return texelFetch(NormalTexture, ipos, SampleIndex).xyz * 2.0 - 1.0;
|
||||
}
|
||||
#else
|
||||
vec3 SampleNormal(vec2 uv)
|
||||
{
|
||||
ivec2 texSize = textureSize(NormalTexture, 0);
|
||||
ivec2 ipos = ivec2(uv * vec2(texSize));
|
||||
return texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Look up the eye space normal for the specified texture coordinate
|
||||
vec3 FetchNormal(vec2 uv)
|
||||
{
|
||||
vec3 normal = SampleNormal(Offset + uv * Scale);
|
||||
if (length(normal) > 0.1)
|
||||
{
|
||||
normal = normalize(normal);
|
||||
normal.z = -normal.z;
|
||||
return normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
return vec3(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute normalized 2D direction
|
||||
vec2 RotateDirection(vec2 dir, vec2 cossin)
|
||||
{
|
||||
return vec2(dir.x * cossin.x - dir.y * cossin.y, dir.x * cossin.y + dir.y * cossin.x);
|
||||
}
|
||||
|
||||
vec4 GetJitter()
|
||||
{
|
||||
#if !defined(USE_RANDOM_TEXTURE)
|
||||
return vec4(1,0,1,1);
|
||||
//vec3 rand = noise3(TexCoord.x + TexCoord.y);
|
||||
//float angle = 2.0 * PI * rand.x / NUM_DIRECTIONS;
|
||||
//return vec4(cos(angle), sin(angle), rand.y, rand.z);
|
||||
#else
|
||||
return texture(RandomTexture, gl_FragCoord.xy / RANDOM_TEXTURE_WIDTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Calculates the ambient occlusion of a sample
|
||||
float ComputeSampleAO(vec3 kernelPos, vec3 normal, vec3 samplePos)
|
||||
{
|
||||
vec3 v = samplePos - kernelPos;
|
||||
float distanceSquare = dot(v, v);
|
||||
float nDotV = dot(normal, v) * inversesqrt(distanceSquare);
|
||||
return clamp(nDotV - NDotVBias, 0.0, 1.0) * clamp(distanceSquare * NegInvR2 + 1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Calculates the total ambient occlusion for the entire fragment
|
||||
float ComputeAO(vec3 viewPosition, vec3 viewNormal)
|
||||
{
|
||||
vec4 rand = GetJitter();
|
||||
|
||||
float radiusPixels = RadiusToScreen / viewPosition.z;
|
||||
float stepSizePixels = radiusPixels / (NUM_STEPS + 1.0);
|
||||
|
||||
const float directionAngleStep = 2.0 * PI / NUM_DIRECTIONS;
|
||||
float ao = 0.0;
|
||||
|
||||
for (float directionIndex = 0.0; directionIndex < NUM_DIRECTIONS; ++directionIndex)
|
||||
{
|
||||
float angle = directionAngleStep * directionIndex;
|
||||
|
||||
vec2 direction = RotateDirection(vec2(cos(angle), sin(angle)), rand.xy);
|
||||
float rayPixels = (rand.z * stepSizePixels + 1.0);
|
||||
|
||||
for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex)
|
||||
{
|
||||
vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord;
|
||||
vec3 samplePos = FetchViewPos(sampleUV);
|
||||
ao += ComputeSampleAO(viewPosition, viewNormal, samplePos);
|
||||
rayPixels += stepSizePixels;
|
||||
}
|
||||
}
|
||||
|
||||
ao *= AOMultiplier / (NUM_DIRECTIONS * NUM_STEPS);
|
||||
return clamp(1.0 - ao * 2.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 viewPosition = FetchViewPos(TexCoord);
|
||||
vec3 viewNormal = FetchNormal(TexCoord);
|
||||
float occlusion = viewNormal != vec3(0.0) ? ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength) : 1.0;
|
||||
|
||||
FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0);
|
||||
}
|
39
wadsrc/static/shaders/glsl/ssaocombine.fp
Normal file
39
wadsrc/static/shaders/glsl/ssaocombine.fp
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
in vec2 TexCoord;
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D AODepthTexture;
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
uniform sampler2DMS SceneFogTexture;
|
||||
uniform int SampleCount;
|
||||
#else
|
||||
uniform sampler2D SceneFogTexture;
|
||||
#endif
|
||||
|
||||
uniform vec2 Scale;
|
||||
uniform vec2 Offset;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = Offset + TexCoord * Scale;
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
ivec2 texSize = textureSize(SceneFogTexture);
|
||||
#else
|
||||
ivec2 texSize = textureSize(SceneFogTexture, 0);
|
||||
#endif
|
||||
ivec2 ipos = ivec2(uv * vec2(texSize));
|
||||
|
||||
#if defined(MULTISAMPLE)
|
||||
vec3 fogColor = vec3(0.0);
|
||||
for (int i = 0; i < SampleCount; i++)
|
||||
fogColor += texelFetch(SceneFogTexture, ipos, i).rgb;
|
||||
fogColor /= float(SampleCount);
|
||||
#else
|
||||
vec3 fogColor = texelFetch(SceneFogTexture, ipos, 0).rgb;
|
||||
#endif
|
||||
|
||||
float attenutation = texture(AODepthTexture, TexCoord).x;
|
||||
FragColor = vec4(fogColor, 1.0 - attenutation);
|
||||
}
|
|
@ -3,6 +3,6 @@ out vec4 FragColor;
|
|||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(1.0);
|
||||
FragColor = vec4(1.0, 1.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue