Implemented automatic tuning of shadow space frustum used for illuminating volumetric effects and particle systems.
--HG-- extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40163
This commit is contained in:
@@ -73,6 +73,20 @@ KRVector3 KRAABB::size() const
|
||||
return max - min;
|
||||
}
|
||||
|
||||
void KRAABB::scale(const KRVector3 &s)
|
||||
{
|
||||
KRVector3 prev_center = center();
|
||||
KRVector3 prev_size = size();
|
||||
KRVector3 new_scale = KRVector3(prev_size.x * s.x, prev_size.y * s.y, prev_size.z * s.z) * 0.5f;
|
||||
min = prev_center - new_scale;
|
||||
max = prev_center + new_scale;
|
||||
}
|
||||
|
||||
void KRAABB::scale(float s)
|
||||
{
|
||||
scale(KRVector3(s));
|
||||
}
|
||||
|
||||
bool KRAABB::operator >(const KRAABB& b) const
|
||||
{
|
||||
// Comparison operators are implemented to allow insertion into sorted containers such as std::set
|
||||
|
||||
@@ -22,6 +22,9 @@ public:
|
||||
KRAABB(const KRVector3 &corner1, const KRVector3 &corner2, const KRMat4 &modelMatrix);
|
||||
~KRAABB();
|
||||
|
||||
void scale(const KRVector3 &s);
|
||||
void scale(float s);
|
||||
|
||||
KRVector3 center() const;
|
||||
KRVector3 size() const;
|
||||
bool intersects(const KRAABB& b) const;
|
||||
|
||||
@@ -119,13 +119,13 @@ KRCamera::KRCamera(KRContext &context) : KRContextObject(context) {
|
||||
volumetric_environment_downsample = 2;
|
||||
volumetric_environment_max_distance = 1000.0f;
|
||||
volumetric_environment_quality = (50 - 5.0) / 495.0f;
|
||||
volumetric_environment_intensity = 1.0f;
|
||||
volumetric_environment_intensity = 0.9f;
|
||||
|
||||
|
||||
fog_near = 500.0f;
|
||||
fog_far = 1000.0f;
|
||||
fog_density = 0.01f;
|
||||
fog_color = KRVector3(0.5, 0.5, 0.5);
|
||||
fog_far = 5000.0f;
|
||||
fog_density = 0.0005f;
|
||||
fog_color = KRVector3(0.45, 0.45, 0.5);
|
||||
fog_type = 0;
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
|
||||
|
||||
|
||||
// Render the geometry
|
||||
scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, false);
|
||||
scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_DEFERRED_LIGHTS, false);
|
||||
|
||||
// ----====---- Opaque Geometry, Deferred rendering Pass 3 ----====----
|
||||
// Set render target
|
||||
@@ -288,13 +288,12 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
|
||||
} else {
|
||||
// ----====---- Generate Shadowmaps for Lights ----====----
|
||||
scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, true);
|
||||
GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y));
|
||||
|
||||
// ----====---- Opaque Geometry, Forward Rendering ----====----
|
||||
|
||||
// Set render target
|
||||
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer));
|
||||
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0));
|
||||
GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y));
|
||||
|
||||
// Disable alpha blending
|
||||
GLDEBUG(glDisable(GL_BLEND));
|
||||
@@ -421,7 +420,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
|
||||
GLDEBUG(glActiveTexture(GL_TEXTURE0));
|
||||
GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeDepthTexture));
|
||||
|
||||
glViewport(0, 0, volumetricLightingViewport.getSize().x, volumetricLightingViewport.getSize().y);
|
||||
GLDEBUG(glViewport(0, 0, volumetricLightingViewport.getSize().x, volumetricLightingViewport.getSize().y));
|
||||
} else {
|
||||
// Enable z-buffer test
|
||||
GLDEBUG(glEnable(GL_DEPTH_TEST));
|
||||
@@ -436,7 +435,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
|
||||
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer));
|
||||
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0));
|
||||
|
||||
glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y);
|
||||
GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,27 +50,48 @@ KRVector3 KRDirectionalLight::getLocalLightDirection() {
|
||||
|
||||
|
||||
int KRDirectionalLight::configureShadowBufferViewports(const KRViewport &viewport) {
|
||||
|
||||
const float KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE = 1.25f; // Scale to apply to view frustrum bounds so that we don't need to refresh shadows on every frame
|
||||
int cShadows = 1;
|
||||
for(int iShadow=0; iShadow < cShadows; iShadow++) {
|
||||
GLfloat shadowMinDepths[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.05, 0.3}};
|
||||
GLfloat shadowMaxDepths[3][3] = {{0.0, 0.0, 1.0},{0.1, 0.0, 0.0},{0.1, 0.3, 1.0}};
|
||||
|
||||
float min_depth = 0.0f;
|
||||
float max_depth = 1.0f;
|
||||
|
||||
KRAABB worldSpacefrustrumSliceBounds = KRAABB(KRVector3(-1.0f, -max_depth, -1.0f), KRVector3(1.0f, -min_depth, 1.0f), KRMat4::Invert(viewport.getViewProjectionMatrix()));
|
||||
worldSpacefrustrumSliceBounds.scale(KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE);
|
||||
|
||||
KRVector3 shadowLook = -KRVector3::Normalize(getWorldLightDirection());
|
||||
|
||||
KRVector3 shadowUp(0.0, 1.0, 0.0);
|
||||
if(KRVector3::Dot(shadowUp, shadowLook) > 0.99f) shadowUp = KRVector3(0.0, 0.0, 1.0); // Ensure shadow look direction is not parallel with the shadowUp direction
|
||||
|
||||
KRMat4 matShadowView = KRMat4::LookAt(viewport.getCameraPosition() - shadowLook, viewport.getCameraPosition(), shadowUp);
|
||||
|
||||
// KRMat4 matShadowView = KRMat4::LookAt(viewport.getCameraPosition() - shadowLook, viewport.getCameraPosition(), shadowUp);
|
||||
// KRMat4 matShadowProjection = KRMat4();
|
||||
// matShadowProjection.scale(0.001, 0.001, 0.001);
|
||||
|
||||
KRMat4 matShadowView = KRMat4::LookAt(worldSpacefrustrumSliceBounds.center() - shadowLook, worldSpacefrustrumSliceBounds.center(), shadowUp);
|
||||
KRMat4 matShadowProjection = KRMat4();
|
||||
matShadowProjection.scale(0.001, 0.001, 0.001);
|
||||
KRAABB shadowSpaceFrustrumSliceBounds = KRAABB(worldSpacefrustrumSliceBounds.min, worldSpacefrustrumSliceBounds.max, KRMat4::Invert(matShadowProjection));
|
||||
KRAABB shadowSpaceSceneBounds = KRAABB(getScene().getRootOctreeBounds().min, getScene().getRootOctreeBounds().max, KRMat4::Invert(matShadowProjection));
|
||||
if(shadowSpaceSceneBounds.min.z < shadowSpaceFrustrumSliceBounds.min.z) shadowSpaceFrustrumSliceBounds.min.z = shadowSpaceSceneBounds.min.z; // Include any potential shadow casters that are outside the view frustrum
|
||||
matShadowProjection.scale(1.0f / shadowSpaceFrustrumSliceBounds.size().x, 1.0f / shadowSpaceFrustrumSliceBounds.size().y, 1.0f / shadowSpaceFrustrumSliceBounds.size().z);
|
||||
|
||||
KRMat4 matBias;
|
||||
matBias.bias();
|
||||
matShadowProjection *= matBias;
|
||||
|
||||
m_shadowViewports[iShadow] = KRViewport(KRVector2(KRENGINE_SHADOW_MAP_WIDTH, KRENGINE_SHADOW_MAP_HEIGHT), matShadowView, matShadowProjection);
|
||||
KRViewport newShadowViewport = KRViewport(KRVector2(KRENGINE_SHADOW_MAP_WIDTH, KRENGINE_SHADOW_MAP_HEIGHT), matShadowView, matShadowProjection);
|
||||
KRAABB prevShadowBounds = KRAABB(-KRVector3::One(), KRVector3::One(), KRMat4::Invert(m_shadowViewports[iShadow].getViewProjectionMatrix()));
|
||||
KRAABB minimumShadowBounds = KRAABB(-KRVector3::One(), KRVector3::One(), KRMat4::Invert(newShadowViewport.getViewProjectionMatrix()));
|
||||
minimumShadowBounds.scale(1.0f / KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE);
|
||||
if(!prevShadowBounds.contains(minimumShadowBounds) || !shadowValid[iShadow]) {
|
||||
m_shadowViewports[iShadow] = newShadowViewport;
|
||||
shadowValid[iShadow] = false;
|
||||
fprintf(stderr, "Kraken - Generate shadow maps...\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -578,8 +578,8 @@ float const PI = 3.141592653589793f;
|
||||
1.0f, 10.0f, 2.0f, 1.0f, 1.0f, 1.0f, 5.0f, 1.0f,
|
||||
0.5f, 1.0f, 2.0f, 2.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f, 1000.0f, 10000.0f,
|
||||
1.0f, 5.0f, 10000.0f, 1.0f, 10.0f,
|
||||
3.0f, 10000.0f, 10000.0f, 0.10f, 1.0f, 1.0f, 1.0f
|
||||
1.0f, 5.0f, 10000.0f, 1.0f, 5.0f,
|
||||
3.0f, 10000.0f, 10000.0f, 0.01f, 1.0f, 1.0f, 1.0f
|
||||
};
|
||||
|
||||
return maxValues[i];
|
||||
|
||||
@@ -256,7 +256,9 @@ void KRLight::deleteBuffers()
|
||||
|
||||
void KRLight::invalidateShadowBuffers()
|
||||
{
|
||||
memset(shadowValid, sizeof(bool) * KRENGINE_MAX_SHADOW_BUFFERS, 0);
|
||||
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
|
||||
shadowValid[iShadow] = false;
|
||||
}
|
||||
}
|
||||
|
||||
int KRLight::configureShadowBufferViewports(const KRViewport &viewport)
|
||||
@@ -265,43 +267,47 @@ int KRLight::configureShadowBufferViewports(const KRViewport &viewport)
|
||||
}
|
||||
|
||||
void KRLight::renderShadowBuffers(KRCamera *pCamera)
|
||||
{
|
||||
{
|
||||
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
|
||||
glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y);
|
||||
|
||||
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]));
|
||||
|
||||
GLDEBUG(glClearDepthf(0.0f));
|
||||
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y);
|
||||
|
||||
GLDEBUG(glClearDepthf(1.0f));
|
||||
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
glViewport(1, 1, m_shadowViewports[iShadow].getSize().x - 2, m_shadowViewports[iShadow].getSize().y - 2);
|
||||
|
||||
GLDEBUG(glDisable(GL_DITHER));
|
||||
|
||||
GLDEBUG(glCullFace(GL_BACK)); // Enable frontface culling, which eliminates some self-cast shadow artifacts
|
||||
GLDEBUG(glEnable(GL_CULL_FACE));
|
||||
|
||||
// Enable z-buffer test
|
||||
GLDEBUG(glEnable(GL_DEPTH_TEST));
|
||||
GLDEBUG(glDepthFunc(GL_LESS));
|
||||
GLDEBUG(glDepthRangef(0.0, 1.0));
|
||||
|
||||
// Disable alpha blending as we are using alpha channel for packed depth info
|
||||
GLDEBUG(glDisable(GL_BLEND));
|
||||
|
||||
// Use shader program
|
||||
KRShader *shadowShader = m_pContext->getShaderManager()->getShader("ShadowShader", pCamera, std::vector<KRLight *>(), false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT);
|
||||
|
||||
getContext().getShaderManager()->selectShader(*pCamera, shadowShader, m_shadowViewports[iShadow], KRMat4(), std::vector<KRLight *>(), KRNode::RENDER_PASS_SHADOWMAP);
|
||||
|
||||
|
||||
getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP, true);
|
||||
if(!shadowValid[iShadow]) {
|
||||
shadowValid[iShadow] = true;
|
||||
|
||||
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]));
|
||||
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0));
|
||||
|
||||
GLDEBUG(glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y));
|
||||
|
||||
|
||||
GLDEBUG(glClearDepthf(0.0f));
|
||||
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
GLDEBUG(glViewport(1, 1, m_shadowViewports[iShadow].getSize().x - 2, m_shadowViewports[iShadow].getSize().y - 2));
|
||||
|
||||
GLDEBUG(glClearDepthf(1.0f));
|
||||
|
||||
GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
GLDEBUG(glDisable(GL_DITHER));
|
||||
|
||||
GLDEBUG(glCullFace(GL_BACK)); // Enable frontface culling, which eliminates some self-cast shadow artifacts
|
||||
GLDEBUG(glEnable(GL_CULL_FACE));
|
||||
|
||||
// Enable z-buffer test
|
||||
GLDEBUG(glEnable(GL_DEPTH_TEST));
|
||||
GLDEBUG(glDepthFunc(GL_LESS));
|
||||
GLDEBUG(glDepthRangef(0.0, 1.0));
|
||||
|
||||
// Disable alpha blending as we are using alpha channel for packed depth info
|
||||
GLDEBUG(glDisable(GL_BLEND));
|
||||
|
||||
// Use shader program
|
||||
KRShader *shadowShader = m_pContext->getShaderManager()->getShader("ShadowShader", pCamera, std::vector<KRLight *>(), false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT);
|
||||
|
||||
getContext().getShaderManager()->selectShader(*pCamera, shadowShader, m_shadowViewports[iShadow], KRMat4(), std::vector<KRLight *>(), KRNode::RENDER_PASS_SHADOWMAP);
|
||||
|
||||
|
||||
getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +315,15 @@ void KRLight::renderShadowBuffers(KRCamera *pCamera)
|
||||
|
||||
int KRLight::getShadowBufferCount()
|
||||
{
|
||||
return m_cShadowBuffers;
|
||||
int cBuffers=0;
|
||||
for(int iBuffer=0; iBuffer < m_cShadowBuffers; iBuffer++) {
|
||||
if(shadowValid[iBuffer]) {
|
||||
cBuffers++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cBuffers;
|
||||
}
|
||||
|
||||
GLuint *KRLight::getShadowTextures()
|
||||
|
||||
@@ -424,6 +424,15 @@ void KRScene::addDefaultLights()
|
||||
{
|
||||
KRDirectionalLight *light1 = new KRDirectionalLight(*this, "default_light1");
|
||||
|
||||
light1->setLocalRotation((KRQuaternion(KRVector3(0.0, M_PI * 0.25, 0.0)) * KRQuaternion(KRVector3(0.0, 0.0, -M_PI * 0.25))).euler());
|
||||
light1->setLocalRotation((KRQuaternion(KRVector3(0.0, M_PI * 0.10, 0.0)) * KRQuaternion(KRVector3(0.0, 0.0, -M_PI * 0.15))).euler());
|
||||
m_pRootNode->addChild(light1);
|
||||
}
|
||||
|
||||
KRAABB KRScene::getRootOctreeBounds()
|
||||
{
|
||||
if(m_nodeTree.getRootNode()) {
|
||||
return m_nodeTree.getRootNode()->getBounds();
|
||||
} else {
|
||||
return KRAABB(-KRVector3::One(), KRVector3::One());
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,8 @@ public:
|
||||
void physicsUpdate(float deltaTime);
|
||||
void addDefaultLights();
|
||||
|
||||
KRAABB getRootOctreeBounds();
|
||||
|
||||
private:
|
||||
KRLight *findFirstLight(KRNode &node);
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 &
|
||||
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
}
|
||||
|
||||
if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE2] != -1 && cShadowBuffers > 1) {
|
||||
if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE2] != -1 && cShadowBuffers > 1 && camera.m_cShadowBuffers > 1) {
|
||||
m_pContext->getTextureManager()->selectTexture(4, NULL);
|
||||
GLDEBUG(glActiveTexture(GL_TEXTURE4));
|
||||
GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[1]));
|
||||
@@ -268,7 +268,7 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 &
|
||||
GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
}
|
||||
|
||||
if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE3] != -1 && cShadowBuffers > 2) {
|
||||
if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE3] != -1 && cShadowBuffers > 2 && camera.m_cShadowBuffers > 2) {
|
||||
m_pContext->getTextureManager()->selectTexture(5, NULL);
|
||||
GLDEBUG(glActiveTexture(GL_TEXTURE5));
|
||||
GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[2]));
|
||||
|
||||
@@ -53,7 +53,7 @@ KRShaderManager::~KRShaderManager() {
|
||||
KRShader *KRShaderManager::getShader(const std::string &shader_name, KRCamera *pCamera, const std::vector<KRLight *> &lights, bool bDiffuseMap, bool bNormalMap, bool bSpecMap, bool bReflectionMap, bool bReflectionCubeMap, bool bLightMap, bool bDiffuseMapScale,bool bSpecMapScale, bool bNormalMapScale, bool bReflectionMapScale, bool bDiffuseMapOffset, bool bSpecMapOffset, bool bNormalMapOffset, bool bReflectionMapOffset, bool bAlphaTest, bool bAlphaBlend, KRNode::RenderPass renderPass) {
|
||||
|
||||
int iShadowQuality = 0; // FINDME - HACK - Placeholder code, need to iterate through lights and dynamically build shader
|
||||
|
||||
|
||||
|
||||
int light_directional_count = 0;
|
||||
int light_point_count = 0;
|
||||
@@ -73,6 +73,9 @@ KRShader *KRShaderManager::getShader(const std::string &shader_name, KRCamera *p
|
||||
}
|
||||
}
|
||||
|
||||
if(iShadowQuality > pCamera->m_cShadowBuffers) {
|
||||
iShadowQuality = pCamera->m_cShadowBuffers;
|
||||
}
|
||||
|
||||
char szKey[256];
|
||||
sprintf(szKey, "%i_%i_%i_%i_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%i_%s_%i_%d_%d_%f_%f_%f_%f_%f_%f_%f", light_directional_count, light_point_count, light_spot_count, pCamera->fog_type, pCamera->bEnablePerPixel,bAlphaTest, bAlphaBlend, bDiffuseMap, bNormalMap, bSpecMap, bReflectionMap, bReflectionCubeMap, pCamera->bDebugPSSM, iShadowQuality, pCamera->bEnableAmbient, pCamera->bEnableDiffuse, pCamera->bEnableSpecular, bLightMap, bDiffuseMapScale, bSpecMapScale, bReflectionMapScale, bNormalMapScale, bDiffuseMapOffset, bSpecMapOffset, bReflectionMapOffset, bNormalMapOffset,pCamera->volumetric_environment_enable && pCamera->volumetric_environment_downsample != 0, renderPass, shader_name.c_str(),pCamera->dof_quality,pCamera->bEnableFlash,pCamera->bEnableVignette,pCamera->dof_depth,pCamera->dof_falloff,pCamera->flash_depth,pCamera->flash_falloff,pCamera->flash_intensity,pCamera->vignette_radius,pCamera->vignette_falloff);
|
||||
|
||||
Reference in New Issue
Block a user