Added support for offscreen rendering and high resolution shadow maps
parent
b033e35385
commit
2665847c41
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue