Added support for offscreen rendering and high resolution shadow maps

master
Tomasz Kapuściński 2015-05-12 13:09:31 +02:00
parent b033e35385
commit 2665847c41
8 changed files with 171 additions and 15 deletions

View File

@ -107,7 +107,8 @@ enum RenderState
RENDER_STATE_DEPTH_WRITE,
RENDER_STATE_ALPHA_TEST,
RENDER_STATE_CULLING,
RENDER_STATE_DEPTH_BIAS
RENDER_STATE_DEPTH_BIAS,
RENDER_STATE_OFFSCREEN_RENDERING
};
/**
@ -380,6 +381,9 @@ public:
//! Sets the current fill mode
virtual void SetFillMode(FillMode mode) = 0;
//! Initializes offscreen buffer
virtual void InitOffscreenBuffer(int width, int height) = 0;
//! Copies content of framebuffer to texture
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) = 0;

View File

@ -355,6 +355,10 @@ FillMode CNullDevice::GetFillMode()
return FILL_POINT;
}
void CNullDevice::InitOffscreenBuffer(int width, int height)
{
}
void CNullDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
{
}

View File

@ -139,6 +139,8 @@ public:
virtual void SetFillMode(FillMode mode) ;
virtual FillMode GetFillMode();
virtual void InitOffscreenBuffer(int width, int height);
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height);
virtual void* GetFrameBufferPixels() const;

View File

@ -128,6 +128,14 @@ enum TexMixArgument
{
//! Color from current texture
TEX_MIX_ARG_TEXTURE,
//! Color from texture unit 0
TEX_MIX_ARG_TEXTURE_0,
//! Color from texture unit 1
TEX_MIX_ARG_TEXTURE_1,
//! Color from texture unit 2
TEX_MIX_ARG_TEXTURE_2,
//! Color from texture unit 3
TEX_MIX_ARG_TEXTURE_3,
//! Color computed by previous texture unit (current in DirectX; previous in OpenGL)
TEX_MIX_ARG_COMPUTED_COLOR,
//! (Source) color of textured fragment (diffuse in DirectX; primary color in OpenGL)

View File

@ -117,7 +117,7 @@ CEngine::CEngine(CApplication *app)
m_textureMipmapLevel = 1;
m_textureAnisotropy = 1;
m_shadowMapping = false;
m_npotShadowMap = false;
m_offscreenShadowRendering = false;
m_totoMode = true;
m_lensMode = true;
m_waterMode = true;
@ -186,7 +186,7 @@ CEngine::CEngine(CApplication *app)
if (CProfile::GetInstance().GetIntProperty("Setup", "ShadowMapping", value))
{
m_shadowMapping = (value > 0);
m_npotShadowMap = (value > 1);
m_offscreenShadowRendering = (value > 1);
}
m_defaultTexParams.format = TEX_IMG_AUTO;
@ -3336,6 +3336,9 @@ void CEngine::Draw3DScene()
params.coords[i].mode = TEX_GEN_NONE;
m_device->SetTextureCoordGeneration(2, params);
m_device->SetTexture(3, 0);
m_device->SetTextureEnabled(3, false);
}
// Draws the shadows , if shadows enabled
@ -3515,8 +3518,6 @@ void CEngine::RenderShadowMap()
m_app->StartPerformanceCounter(PCNT_RENDER_SHADOW_MAP);
m_device->Clear();
// If no shadow map texture exists, create it
if (m_shadowMap.id == 0)
{
@ -3524,9 +3525,18 @@ void CEngine::RenderShadowMap()
int depth = m_app->GetInstance().GetVideoConfig().depthSize;
if (m_npotShadowMap)
if (m_offscreenShadowRendering)
{
width = height = Math::Min(m_size.x, m_size.y);
int size;
if (CProfile::GetInstance().GetIntProperty("Setup", "OffscreenBuffer", size))
{
width = height = size;
}
else
{
width = height = 2048;
}
}
else
{
@ -3542,12 +3552,23 @@ void CEngine::RenderShadowMap()
m_shadowMap = m_device->CreateDepthTexture(width, height, depth);
if (m_offscreenShadowRendering)
{
m_device->InitOffscreenBuffer(width, height);
}
GetLogger()->Info("Created shadow map texture: %dx%d, depth %d\n", width, height, depth);
}
if (m_offscreenShadowRendering)
{
m_device->SetRenderState(RENDER_STATE_OFFSCREEN_RENDERING, true);
}
m_device->Clear();
// change state to rendering shadow maps
m_device->SetColorMask(false, false, false, false);
//m_device->SetDepthTestFunc(COMP_FUNC_LEQUAL);
m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, true);
m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, true);
m_device->SetRenderState(RENDER_STATE_BLENDING, false);
@ -3561,16 +3582,18 @@ void CEngine::RenderShadowMap()
// recompute matrices
Math::Vector worldUp(1.0f, 0.0f, 0.0f);
Math::Vector dir = m_lookatPt - m_eyePt;
float change = Math::Max(1.0f, dir.Length() / 25.0f);
float change = Math::Max(0.5f, (5.0f + dir.Length()) / 25.0f);
dir.Normalize();
Math::Vector pos = m_lookatPt + 40.0f * dir;
Math::Vector lightPos = pos + Math::Vector(3.0f, 30.0f, 3.0f);
Math::Vector lookAt = pos + Math::Vector(0.0, 100.0f, 0.0f);
float dist = 75.0f; // *change;
float dist = 75.0f * change;
Math::LoadOrthoProjectionMatrix(m_shadowProjMat, -dist, dist, -dist, dist, -50.0f, 50.0f);
if (m_offscreenShadowRendering) dist = 400.0f * change;
Math::LoadOrthoProjectionMatrix(m_shadowProjMat, -dist, dist, -dist, dist, -200.0f, 200.0f);
Math::LoadViewMatrix(m_shadowViewMat, lightPos, lookAt, worldUp);
Math::Matrix temporary = Math::MultiplyMatrices(m_shadowProjMat, m_shadowViewMat);
@ -3642,12 +3665,16 @@ void CEngine::RenderShadowMap()
}
}
m_device->SetCullMode(CULL_CCW);
m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, false);
//m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, false);
// copy depth buffer to shadow map
m_device->CopyFramebufferToTexture(m_shadowMap, 0, 0, 0, 0, m_shadowMap.size.x, m_shadowMap.size.y);
if (m_offscreenShadowRendering)
{
m_device->SetRenderState(RENDER_STATE_OFFSCREEN_RENDERING, false);
}
// restore default state
m_device->SetViewport(0, 0, m_size.x, m_size.y);

View File

@ -1457,8 +1457,8 @@ protected:
int m_textureAnisotropy;
//! true if shadow mapping enabled
bool m_shadowMapping;
//! Override for NPOT shadow map texture
bool m_npotShadowMap;
//! true enables offscreen shadow rendering
bool m_offscreenShadowRendering;
//! Map of loaded textures (by name)
std::map<std::string, Texture> m_texNameMap;

View File

@ -75,6 +75,10 @@ CGLDevice::CGLDevice(const GLDeviceConfig &config)
m_glMajor = 1;
m_glMinor = 1;
m_shadowMappingSupport = SMS_NONE;
m_framebuffer = 0;
m_colorBuffer = 0;
m_depthBuffer = 0;
}
@ -217,6 +221,15 @@ bool CGLDevice::Create()
if (!m_multitextureAvailable)
GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n");
m_framebufferObject = glewIsSupported("GL_EXT_framebuffer_object");
if (m_framebufferObject)
{
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &m_maxRenderbufferSize);
GetLogger()->Info("Offscreen rendering available\n");
GetLogger()->Info("Maximum renderbuffer size: %d\n", m_maxRenderbufferSize);
}
// Detect Shadow mapping support
if (m_glMajor >= 2 || m_glMinor >= 4) // Core depth texture+shadow, OpenGL 1.4+
{
@ -1054,6 +1067,14 @@ void CGLDevice::UpdateTextureParams(int index)
// Color arg1
if (params.colorArg1 == TEX_MIX_ARG_TEXTURE)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1);
else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_2)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE2);
else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_3)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE3);
else if (params.colorArg1 == TEX_MIX_ARG_COMPUTED_COLOR)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
else if (params.colorArg1 == TEX_MIX_ARG_SRC_COLOR)
@ -1065,6 +1086,14 @@ void CGLDevice::UpdateTextureParams(int index)
// Color arg2
if (params.colorArg2 == TEX_MIX_ARG_TEXTURE)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0);
else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1);
else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_2)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE2);
else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_3)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE3);
else if (params.colorArg2 == TEX_MIX_ARG_COMPUTED_COLOR)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
else if (params.colorArg2 == TEX_MIX_ARG_SRC_COLOR)
@ -1097,6 +1126,14 @@ after_tex_color:
// Alpha arg1
if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE1);
else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_2)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE2);
else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_3)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE3);
else if (params.alphaArg1 == TEX_MIX_ARG_COMPUTED_COLOR)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
else if (params.alphaArg1 == TEX_MIX_ARG_SRC_COLOR)
@ -1108,6 +1145,14 @@ after_tex_color:
// Alpha arg2
if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE0);
else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE1);
else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_2)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE2);
else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_3)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE3);
else if (params.alphaArg2 == TEX_MIX_ARG_COMPUTED_COLOR)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
else if (params.alphaArg2 == TEX_MIX_ARG_SRC_COLOR)
@ -1728,6 +1773,21 @@ void CGLDevice::SetRenderState(RenderState state, bool enabled)
return;
}
else if (state == RENDER_STATE_OFFSCREEN_RENDERING)
{
if (!m_framebufferObject)
{
GetLogger()->Error("Cannot enable offscreen rendering without framebuffer object!\n");
return;
}
if (m_framebuffer == 0)
InitOffscreenBuffer(2048, 2048);
GLuint toBind = (enabled ? m_framebuffer : 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, toBind);
}
GLenum flag = 0;
@ -1895,6 +1955,42 @@ void CGLDevice::SetFillMode(FillMode mode)
else assert(false);
}
void CGLDevice::InitOffscreenBuffer(int width, int height)
{
if (!m_framebufferObject) return;
width = Math::Min(width, m_maxRenderbufferSize);
height = Math::Min(height, m_maxRenderbufferSize);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
if (m_colorBuffer != 0)
glDeleteRenderbuffersEXT(1, &m_colorBuffer);
glGenRenderbuffersEXT(1, &m_colorBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_colorBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
if (m_depthBuffer != 0)
glDeleteRenderbuffersEXT(1, &m_depthBuffer);
glGenRenderbuffersEXT(1, &m_depthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
if (m_framebuffer == 0)
glGenFramebuffersEXT(1, &m_framebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_framebuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_colorBuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GetLogger()->Info("Initialized offscreen buffer %dx%d\n", width, height);
}
void CGLDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
{
if (texture.id == 0) return;

View File

@ -26,6 +26,7 @@
#include "graphics/core/device.h"
#include "GL/glew.h"
#include <string>
#include <vector>
@ -197,6 +198,8 @@ public:
virtual void SetFillMode(FillMode mode) OVERRIDE;
virtual void InitOffscreenBuffer(int width, int height) OVERRIDE;
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) OVERRIDE;
virtual void* GetFrameBufferPixels() const OVERRIDE;
@ -272,12 +275,24 @@ private:
bool m_anisotropyAvailable;
//! Maximum anisotropy level
int m_maxAnisotropy;
//! Whether offscreen rendering is available
bool m_framebufferObject;
//! Which vertex buffer type to use
VertexBufferType m_vertexBufferType;
//! Map of saved VBO objects
std::map<unsigned int, VboObjectInfo> m_vboObjects;
//! Last ID of VBO object
unsigned int m_lastVboId;
// Offscreen buffer
//! Framebuffer object
GLuint m_framebuffer;
//! Color renderbuffer
GLuint m_colorBuffer;
//! Depth renderbuffer
GLuint m_depthBuffer;
//! Maximum available renderbuffer size
int m_maxRenderbufferSize;
};