From 62c285f7b3cc83a1434ff39ee7aec49dfd38d343 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 1 Mar 2017 17:17:33 +0100 Subject: [PATCH] Create a shadowmap texture and upload light list --- src/gl/dynlights/gl_shadowmap.cpp | 50 ++++++++++++++++++++++--- src/gl/dynlights/gl_shadowmap.h | 4 ++ src/gl/renderer/gl_renderbuffers.cpp | 38 +++++++++++++++++++ src/gl/renderer/gl_renderbuffers.h | 8 ++++ wadsrc/static/shaders/glsl/shadowmap.fp | 18 ++++++++- 5 files changed, 111 insertions(+), 7 deletions(-) diff --git a/src/gl/dynlights/gl_shadowmap.cpp b/src/gl/dynlights/gl_shadowmap.cpp index 9de8e3697..d0b6f7715 100644 --- a/src/gl/dynlights/gl_shadowmap.cpp +++ b/src/gl/dynlights/gl_shadowmap.cpp @@ -28,27 +28,32 @@ #include "gl/system/gl_debug.h" #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_postprocessstate.h" +#include "gl/renderer/gl_renderbuffers.h" #include "gl/shaders/gl_shadowmapshader.h" #include "r_state.h" void FShadowMap::Clear() { + if (mLightList != 0) + { + glDeleteBuffers(1, (GLuint*)&mLightList); + mLightList = 0; + } + mLightBSP.Clear(); } void FShadowMap::Update() { - TThinkerIterator it(STAT_DLIGHT); - while (true) - { - ADynamicLight *light = it.Next(); - if (!light) break; - } + UploadLights(); FGLDebug::PushGroup("ShadowMap"); FGLPostProcessState savedState; + GLRenderer->mBuffers->BindShadowMapFB(); + GLRenderer->mShadowMapShader->Bind(); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, mLightList); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, mLightBSP.GetNodesBuffer()); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, mLightBSP.GetSegsBuffer()); @@ -58,8 +63,41 @@ void FShadowMap::Update() const auto &viewport = GLRenderer->mScreenViewport; glViewport(viewport.left, viewport.top, viewport.width, viewport.height); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, 0); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, 0); FGLDebug::PopGroup(); } + +void FShadowMap::UploadLights() +{ + lights.Clear(); + + TThinkerIterator it(STAT_DLIGHT); + while (true) + { + ADynamicLight *light = it.Next(); + if (!light) break; + + lights.Push(light->X()); + lights.Push(light->Y()); + lights.Push(light->Z()); + lights.Push(light->GetRadius()); + + if (lights.Size() == 1024) // Only 1024 lights for now + break; + } + + while (lights.Size() < 1024 * 4) + lights.Push(0.0f); + + if (mLightList == 0) + glGenBuffers(1, (GLuint*)&mLightList); + + int oldBinding = 0; + glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &oldBinding); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, mLightList); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * lights.Size(), &lights[0], GL_STATIC_DRAW); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); +} \ No newline at end of file diff --git a/src/gl/dynlights/gl_shadowmap.h b/src/gl/dynlights/gl_shadowmap.h index 86a97dce5..1289965f2 100644 --- a/src/gl/dynlights/gl_shadowmap.h +++ b/src/gl/dynlights/gl_shadowmap.h @@ -13,7 +13,11 @@ public: void Update(); private: + void UploadLights(); + FLightBSP mLightBSP; + int mLightList = 0; + TArray lights; FShadowMap(const FShadowMap &) = delete; FShadowMap &operator=(FShadowMap &) = delete; diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index fad79767c..67b0a0759 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -741,6 +741,44 @@ void FGLRenderBuffers::BindEyeFB(int eye, bool readBuffer) glBindFramebuffer(readBuffer ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER, mEyeFBs[eye]); } +//========================================================================== +// +// Shadow map texture and frame buffers +// +//========================================================================== + +void FGLRenderBuffers::BindShadowMapFB() +{ + CreateShadowMap(); + glBindFramebuffer(GL_FRAMEBUFFER, mShadowMapFB); +} + +void FGLRenderBuffers::BindShadowMapTexture(int texunit) +{ + CreateShadowMap(); + glActiveTexture(GL_TEXTURE0 + texunit); + glBindTexture(GL_TEXTURE_2D, mShadowMapTexture); +} + +void FGLRenderBuffers::CreateShadowMap() +{ + if (mShadowMapTexture != 0) + return; + + GLint activeTex, textureBinding, frameBufferBinding; + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); + glActiveTexture(GL_TEXTURE0); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &frameBufferBinding); + + mShadowMapTexture = Create2DTexture("ShadowMap", GL_R32F, 1024, 1024); + mShadowMapFB = CreateFrameBuffer("ShadowMapFB", mShadowMapTexture); + + glBindTexture(GL_TEXTURE_2D, textureBinding); + glActiveTexture(activeTex); + glBindFramebuffer(GL_FRAMEBUFFER, frameBufferBinding); +} + //========================================================================== // // Makes the scene frame buffer active (multisample, depth, stecil, etc.) diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index f2f7b7cb9..5df3bcca0 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -49,6 +49,9 @@ public: void BindEyeTexture(int eye, int texunit); void BindEyeFB(int eye, bool readBuffer = false); + void BindShadowMapFB(); + void BindShadowMapTexture(int index); + enum { NumBloomLevels = 4 }; FGLBloomTextureLevel BloomLevels[NumBloomLevels]; @@ -89,6 +92,7 @@ private: void CreateBloom(int width, int height); void CreateExposureLevels(int width, int height); void CreateEyeBuffers(int eye); + void CreateShadowMap(); 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); @@ -133,6 +137,10 @@ private: TArray mEyeTextures; TArray mEyeFBs; + // Shadow map texture + GLuint mShadowMapTexture = 0; + GLuint mShadowMapFB = 0; + static bool FailedCreate; static bool BuffersActive; }; diff --git a/wadsrc/static/shaders/glsl/shadowmap.fp b/wadsrc/static/shaders/glsl/shadowmap.fp index 72171244b..ed530e2dd 100644 --- a/wadsrc/static/shaders/glsl/shadowmap.fp +++ b/wadsrc/static/shaders/glsl/shadowmap.fp @@ -16,6 +16,11 @@ struct GPUSeg vec4 bSolid; }; +layout(std430, binding = 1) buffer LightList +{ + vec4 lights[]; +}; + layout(std430, binding = 2) buffer LightNodes { GPUNode bspNodes[]; @@ -112,5 +117,16 @@ float rayTest(vec2 from, vec2 to) void main() { - FragColor = vec4(rayTest(vec2(0.0, 0.0), vec2(1.0, 1.0))); + int lightIndex = int(gl_FragCoord.y); + int x = int(gl_FragCoord.x); + + vec4 light = lights[lightIndex]; + float radius = light.w; + vec2 lightpos = light.xy; + vec2 pixelpos = lightpos + vec2(10.0); + + if (radius > 0.0) + FragColor = vec4(rayTest(lightpos, pixelpos), 0.0, 0.0, 1.0); + else + FragColor = vec4(1.0, 0.0, 0.0, 1.0); }