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:
kearwood
2012-11-22 09:02:25 +00:00
parent 002ad4bda6
commit 230dd4722d
10 changed files with 121 additions and 56 deletions

View File

@@ -73,6 +73,20 @@ KRVector3 KRAABB::size() const
return max - min; 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 bool KRAABB::operator >(const KRAABB& b) const
{ {
// Comparison operators are implemented to allow insertion into sorted containers such as std::set // Comparison operators are implemented to allow insertion into sorted containers such as std::set

View File

@@ -22,6 +22,9 @@ public:
KRAABB(const KRVector3 &corner1, const KRVector3 &corner2, const KRMat4 &modelMatrix); KRAABB(const KRVector3 &corner1, const KRVector3 &corner2, const KRMat4 &modelMatrix);
~KRAABB(); ~KRAABB();
void scale(const KRVector3 &s);
void scale(float s);
KRVector3 center() const; KRVector3 center() const;
KRVector3 size() const; KRVector3 size() const;
bool intersects(const KRAABB& b) const; bool intersects(const KRAABB& b) const;

View File

@@ -119,13 +119,13 @@ KRCamera::KRCamera(KRContext &context) : KRContextObject(context) {
volumetric_environment_downsample = 2; volumetric_environment_downsample = 2;
volumetric_environment_max_distance = 1000.0f; volumetric_environment_max_distance = 1000.0f;
volumetric_environment_quality = (50 - 5.0) / 495.0f; volumetric_environment_quality = (50 - 5.0) / 495.0f;
volumetric_environment_intensity = 1.0f; volumetric_environment_intensity = 0.9f;
fog_near = 500.0f; fog_near = 500.0f;
fog_far = 1000.0f; fog_far = 5000.0f;
fog_density = 0.01f; fog_density = 0.0005f;
fog_color = KRVector3(0.5, 0.5, 0.5); fog_color = KRVector3(0.45, 0.45, 0.5);
fog_type = 0; fog_type = 0;
} }
@@ -244,7 +244,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
// Render the geometry // 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 ----====---- // ----====---- Opaque Geometry, Deferred rendering Pass 3 ----====----
// Set render target // Set render target
@@ -288,13 +288,12 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
} else { } else {
// ----====---- Generate Shadowmaps for Lights ----====---- // ----====---- Generate Shadowmaps for Lights ----====----
scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, true); 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 ----====---- // ----====---- Opaque Geometry, Forward Rendering ----====----
// Set render target // Set render target
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer)); GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer));
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0)); 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 // Disable alpha blending
GLDEBUG(glDisable(GL_BLEND)); GLDEBUG(glDisable(GL_BLEND));
@@ -421,7 +420,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
GLDEBUG(glActiveTexture(GL_TEXTURE0)); GLDEBUG(glActiveTexture(GL_TEXTURE0));
GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeDepthTexture)); 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 { } else {
// Enable z-buffer test // Enable z-buffer test
GLDEBUG(glEnable(GL_DEPTH_TEST)); GLDEBUG(glEnable(GL_DEPTH_TEST));
@@ -436,7 +435,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) {
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer)); GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer));
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0)); 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));
} }
} }

View File

@@ -50,27 +50,48 @@ KRVector3 KRDirectionalLight::getLocalLightDirection() {
int KRDirectionalLight::configureShadowBufferViewports(const KRViewport &viewport) { 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; int cShadows = 1;
for(int iShadow=0; iShadow < cShadows; iShadow++) { 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 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}}; 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 shadowLook = -KRVector3::Normalize(getWorldLightDirection());
KRVector3 shadowUp(0.0, 1.0, 0.0); 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 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(); 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; KRMat4 matBias;
matBias.bias(); matBias.bias();
matShadowProjection *= matBias; 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; return 1;

View File

@@ -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, 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, 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, 1.0f, 1.0f, 1.0f, 1000.0f, 10000.0f,
1.0f, 5.0f, 10000.0f, 1.0f, 10.0f, 1.0f, 5.0f, 10000.0f, 1.0f, 5.0f,
3.0f, 10000.0f, 10000.0f, 0.10f, 1.0f, 1.0f, 1.0f 3.0f, 10000.0f, 10000.0f, 0.01f, 1.0f, 1.0f, 1.0f
}; };
return maxValues[i]; return maxValues[i];

View File

@@ -256,7 +256,9 @@ void KRLight::deleteBuffers()
void KRLight::invalidateShadowBuffers() 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) int KRLight::configureShadowBufferViewports(const KRViewport &viewport)
@@ -267,41 +269,45 @@ int KRLight::configureShadowBufferViewports(const KRViewport &viewport)
void KRLight::renderShadowBuffers(KRCamera *pCamera) void KRLight::renderShadowBuffers(KRCamera *pCamera)
{ {
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) { for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y); if(!shadowValid[iShadow]) {
shadowValid[iShadow] = true;
GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow])); GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]));
GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0));
GLDEBUG(glClearDepthf(0.0f)); GLDEBUG(glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y));
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); 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() 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() GLuint *KRLight::getShadowTextures()

View File

@@ -424,6 +424,15 @@ void KRScene::addDefaultLights()
{ {
KRDirectionalLight *light1 = new KRDirectionalLight(*this, "default_light1"); 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); m_pRootNode->addChild(light1);
} }
KRAABB KRScene::getRootOctreeBounds()
{
if(m_nodeTree.getRootNode()) {
return m_nodeTree.getRootNode()->getBounds();
} else {
return KRAABB(-KRVector3::One(), KRVector3::One());
}
}

View File

@@ -76,6 +76,8 @@ public:
void physicsUpdate(float deltaTime); void physicsUpdate(float deltaTime);
void addDefaultLights(); void addDefaultLights();
KRAABB getRootOctreeBounds();
private: private:
KRLight *findFirstLight(KRNode &node); KRLight *findFirstLight(KRNode &node);

View File

@@ -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)); 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); m_pContext->getTextureManager()->selectTexture(4, NULL);
GLDEBUG(glActiveTexture(GL_TEXTURE4)); GLDEBUG(glActiveTexture(GL_TEXTURE4));
GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[1])); 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)); 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); m_pContext->getTextureManager()->selectTexture(5, NULL);
GLDEBUG(glActiveTexture(GL_TEXTURE5)); GLDEBUG(glActiveTexture(GL_TEXTURE5));
GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[2])); GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[2]));

View File

@@ -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]; 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); 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);