Commit f983396c authored by Ken Martin's avatar Ken Martin

Improve the shadow maps in VTK

This patch changes how the shadow maps work so that
less shadow code is in the mappers. Now the mappers get
a key that contains the shadow map pass and they let
that pass handle setting up shader code and uniforms.

Also changed the shadow map algorithm slightly.  The old approach did
a 1/3 weighting of pixels (0,0) (1,0) and (0,1)  This new algorithm
does a 2x2 box convolution against the 3x3 pixel neighborhood.
It takes 9 tex lookups but produces much nicer results.
parent df44c5c9
......@@ -243,8 +243,8 @@ void vtkDepthOfFieldPass::Render(const vtkRenderState *s)
renWin->GetShaderCache()->ReadyShaderProgram(this->BlurProgram->Program);
}
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
this->Pass1->Activate();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
......
......@@ -580,78 +580,18 @@ void vtkOpenGLPolyDataMapper::ReplaceShaderLight(
// check for shadow maps
vtkInformation *info = actor->GetPropertyKeys();
std::string shadowFactor = "";
if (info && info->Has(vtkShadowMapPass::ShadowMapTextures()))
if (info && info->Has(vtkShadowMapPass::ShadowMapPass()))
{
int *shadowMapTextures = 0;
int numLights = 0;
shadowMapTextures = info->Get(vtkShadowMapPass::ShadowMapTextures());
numLights = info->Length(vtkShadowMapPass::ShadowMapTextures());
// count how many lights have shadow maps
int numSMT = 0;
for (int i = 0; i < numLights; i++)
vtkShadowMapPass *smp = vtkShadowMapPass::SafeDownCast(
info->Get(vtkShadowMapPass::ShadowMapPass()));
if (smp)
{
if (shadowMapTextures[i] >= 0)
{
numSMT++;
}
}
std::ostringstream toString;
toString << numSMT;
vtkShaderProgram::Substitute(FSSource,"//VTK::Light::Dec",
"//VTK::Light::Dec\n"
"#define VTK_NUM_SHADOW_MAPS " + toString.str() + "\n"
// "uniform sampler2DShadow shadowMaps[VTK_NUM_SHADOW_MAPS];\n"
"uniform sampler2D shadowMaps[VTK_NUM_SHADOW_MAPS];\n"
"uniform mat4 shadowTransforms[VTK_NUM_SHADOW_MAPS];\n"
, false);
// build the code for the lighting factors
std::string lfc =
"float factors[6];\n"
"vec4 shadowCoord;\n"
"float result;\n";
numSMT = 0;
for (int i = 0; i < 6; i++)
{
toString.str("");
toString.clear();
toString << i;
if (shadowMapTextures[i] >= 0 && i < numLights)
{
std::ostringstream toString2;
toString2 << numSMT;
lfc +=
" shadowCoord = shadowTransforms[" + toString2.str() + "]*vertexVC;\n"
" result = 1.0;\n"
" if(shadowCoord.w > 0.0)\n"
" {\n"
" vec2 projected = shadowCoord.xy/shadowCoord.w;\n"
" if(projected.x >= 0.0 && projected.x <= 1.0\n"
" && projected.y >= 0.0 && projected.y <= 1.0)\n"
" {\n"
" result = 0.0;\n"
" float zval = shadowCoord.z - 0.005;\n"
" if (textureProjOffset(shadowMaps[" + toString2.str() + "],shadowCoord,ivec2( 0, 0)).r - zval > 0) { result += 0.34; }\n"
" if (textureProjOffset(shadowMaps[" + toString2.str() + "],shadowCoord,ivec2( 0, 1)).r - zval > 0) { result += 0.33; }\n"
" if (textureProjOffset(shadowMaps[" + toString2.str() + "],shadowCoord,ivec2( 1, 0)).r - zval > 0) { result += 0.33; }\n"
" }\n"
" }\n"
" factors[" + toString.str() + "] = result;\n";
numSMT++;
}
else
{
lfc += " factors[" + toString.str() + "] = 1.0;\n";
}
vtkShaderProgram::Substitute(FSSource,"//VTK::Light::Dec",
smp->GetFragmentDeclaration(), false);
vtkShaderProgram::Substitute(FSSource,"//VTK::Light::Impl",
smp->GetFragmentImplementation(), false);
shadowFactor = "*factors[lightNum]";
}
lfc += "//VTK::Light::Impl";
vtkShaderProgram::Substitute(FSSource,"//VTK::Light::Impl",
lfc.c_str(), false);
shadowFactor = "*factors[lightNum]";
}
switch (this->LastLightComplexity[this->LastBoundBO])
......@@ -1598,30 +1538,14 @@ void vtkOpenGLPolyDataMapper::SetLightingShaderParameters(
// check for shadow maps
vtkInformation *info = actor->GetPropertyKeys();
if (info && info->Has(vtkShadowMapPass::ShadowMapTextures()))
if (info && info->Has(vtkShadowMapPass::ShadowMapPass()))
{
int *shadowMapTextures = info->Get(vtkShadowMapPass::ShadowMapTextures());
double *shadowTransforms = info->Get(vtkShadowMapPass::ShadowMapTransforms());
int numLights = info->Length(vtkShadowMapPass::ShadowMapTextures());
// how many lights have shadow maps
int numSMT = 0;
int tunits[6];
float transforms[6*16];
for (int i = 0; i < numLights; i++)
vtkShadowMapPass *smp = vtkShadowMapPass::SafeDownCast(
info->Get(vtkShadowMapPass::ShadowMapPass()));
if (smp)
{
if (shadowMapTextures[i] >= 0)
{
tunits[numSMT] = shadowMapTextures[i];
for (int j = 0; j < 16; j++)
{
transforms[numSMT*16+j] = shadowTransforms[numSMT*16+j];
}
numSMT++;
}
smp->SetUniforms(program);
}
program->SetUniform1iv("shadowMaps", numSMT, tunits);
program->SetUniformMatrix4x4v("shadowTransforms", numSMT, transforms);
}
// for lightkit case there are some parameters to set
......
......@@ -475,8 +475,10 @@ void vtkShadowMapBakerPass::Render(const vtkRenderState *s)
map->SetContext(context);
// map->SetDepthTextureCompare(true);
map->SetLinearMagnification(true);
map->SetMinificationFilter(vtkTextureObject::Linear);
// map->SetLinearMagnification(true);
// map->SetMinificationFilter(vtkTextureObject::Linear);
map->SetLinearMagnification(false);
map->SetMinificationFilter(vtkTextureObject::Nearest);
map->SetWrapS(vtkTextureObject::ClampToEdge);
map->SetWrapT(vtkTextureObject::ClampToEdge);
map->SetWrapR(vtkTextureObject::ClampToEdge);
......
......@@ -24,9 +24,7 @@
#include "vtkImplicitHalo.h"
#include "vtkImplicitSum.h"
#include "vtkInformation.h"
#include "vtkInformationDoubleVectorKey.h"
#include "vtkInformationIntegerKey.h"
#include "vtkInformationIntegerVectorKey.h"
#include "vtkInformationObjectBaseKey.h"
#include "vtkLight.h"
#include "vtkLightCollection.h"
#include "vtkLightsPass.h"
......@@ -43,6 +41,7 @@
#include "vtkRenderState.h"
#include "vtkSampleFunction.h"
#include "vtkSequencePass.h"
#include "vtkShaderProgram.h"
#include "vtkShadowMapBakerPass.h"
#include "vtkTextureObject.h"
#include "vtkTextureUnitManager.h"
......@@ -70,8 +69,7 @@ vtkCxxSetObjectMacro(vtkShadowMapPass,ShadowMapBakerPass,
vtkCxxSetObjectMacro(vtkShadowMapPass,OpaqueSequence,
vtkRenderPass);
vtkInformationKeyMacro(vtkShadowMapPass,ShadowMapTextures,IntegerVector);
vtkInformationKeyMacro(vtkShadowMapPass,ShadowMapTransforms,DoubleVector);
vtkInformationKeyMacro(vtkShadowMapPass,ShadowMapPass,ObjectBase);
// ----------------------------------------------------------------------------
......@@ -199,8 +197,8 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
}
vtkLightCollection *lights=r->GetLights();
std::vector<int> shadowTextureUnits;
shadowTextureUnits.resize(lights->GetNumberOfItems());
this->ShadowTextureUnits.clear();
this->ShadowTextureUnits.resize(lights->GetNumberOfItems());
// get the shadow maps and activate them
int shadowingLightIndex = 0;
......@@ -209,7 +207,7 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
for (lights->InitTraversal(), light = lights->GetNextItem();
light != 0; light = lights->GetNextItem(), lightIndex++)
{
shadowTextureUnits[lightIndex] = -1;
this->ShadowTextureUnits[lightIndex] = -1;
if(light->GetSwitch() &&
this->ShadowMapBakerPass->LightCreatesShadow(light) )
{
......@@ -218,9 +216,7 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
static_cast<size_t>(shadowingLightIndex)];
// activate the texture map
map->Activate();
shadowTextureUnits[lightIndex] = map->GetTextureUnit();
// create some extra shader code for this light
this->ShadowTextureUnits[lightIndex] = map->GetTextureUnit();
shadowingLightIndex++;
}
}
......@@ -248,12 +244,12 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
transform->Translate(0.5,0.5,0.5); // bias
transform->Scale(0.5,0.5,0.5); // scale
this->ShadowTransforms.clear();
shadowingLightIndex = 0;
std::vector<double> shadowTransforms;
for (lights->InitTraversal(), light = lights->GetNextItem(), lightIndex = 0;
light != 0; light = lights->GetNextItem(), lightIndex++)
{
if (shadowTextureUnits[lightIndex] >= 0)
if (this->ShadowTextureUnits[lightIndex] >= 0)
{
vtkCamera *lightCamera=
(*this->ShadowMapBakerPass->GetLightCameras())[
......@@ -270,13 +266,16 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
{
for (int j = 0; j < 4; j++)
{
shadowTransforms.push_back(tmp->Element[i][j]);
this->ShadowTransforms.push_back(tmp->Element[i][j]);
}
}
++shadowingLightIndex;
}
}
// build the shader code
this->BuildShaderCode();
// set the prop keys
int c = s->GetPropArrayCount();
for (int i = 0; i < c; i++)
......@@ -289,12 +288,7 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
p->SetPropertyKeys(info);
info->Delete();
}
info->Set(vtkShadowMapPass::ShadowMapTextures(),
&(shadowTextureUnits[0]),
static_cast<int>(shadowTextureUnits.size()));
info->Set(vtkShadowMapPass::ShadowMapTransforms(),
&(shadowTransforms[0]),
static_cast<int>(shadowTransforms.size()));
info->Set(vtkShadowMapPass::ShadowMapPass(), this);
}
viewCamera_Inv->Delete();
......@@ -324,11 +318,6 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
}
}
#ifdef VTK_SHADOW_MAP_PASS_DEBUG
cout << "finish after rendering geometry without shadowing lights" << endl;
glFinish();
#endif
}
else
{
......@@ -338,6 +327,123 @@ void vtkShadowMapPass::Render(const vtkRenderState *s)
vtkOpenGLCheckErrorMacro("failed after Render");
}
void vtkShadowMapPass::SetUniforms(vtkShaderProgram *program)
{
size_t numLights = this->ShadowTextureUnits.size();
// how many lights have shadow maps
int numSMT = 0;
float transform[16];
std::ostringstream toString;
for (size_t i = 0; i < numLights; i++)
{
if (this->ShadowTextureUnits[i] >= 0)
{
for (int j = 0; j < 16; j++)
{
transform[j] = this->ShadowTransforms[numSMT*16 + j];
}
toString.str("");
toString.clear();
toString << numSMT;
program->SetUniformi(
std::string("shadowMap"+toString.str()).c_str(),
this->ShadowTextureUnits[i]);
program->SetUniformMatrix4x4(
std::string("shadowTransform"+toString.str()).c_str(),
transform);
numSMT++;
}
}
}
void vtkShadowMapPass::BuildShaderCode()
{
size_t numLights = this->ShadowTextureUnits.size();
// count how many lights have shadow maps
int numSMT = 0;
for (size_t i = 0; i < numLights; i++)
{
if (this->ShadowTextureUnits[i] >= 0)
{
numSMT++;
}
}
std::ostringstream toString;
toString.str("");
toString.clear();
toString << this->ShadowMapBakerPass->GetResolution();
std::string fdec = "//VTK::Light::Dec\n"
"float calcShadow(in vec4 vert, in sampler2D shadowMap, in mat4 shadowTransform)\n"
"{\n"
" vec4 shadowCoord = shadowTransform*vert;\n"
" float result = 1.0;\n"
" if(shadowCoord.w > 0.0)\n"
" {\n"
" vec2 projected = shadowCoord.xy/shadowCoord.w;\n"
" if(projected.x >= 0.0 && projected.x <= 1.0\n"
" && projected.y >= 0.0 && projected.y <= 1.0)\n"
" {\n"
" result = 0.0;\n"
" float zval = shadowCoord.z - 0.005;\n"
" vec2 projT = projected*" + toString.str() + ";\n"
" projT = fract(projT);\n"
" if (texture2D(shadowMap,projected + (vec2(-1.0,-1.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + (1.0-projT.x)*(1.0-projT.y); }\n"
" if (texture2D(shadowMap,projected + (vec2(0.0,-1.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + (1.0-projT.y); }\n"
" if (texture2D(shadowMap,projected + (vec2(1.0,-1.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + projT.x*(1.0-projT.y); }\n"
" if (texture2D(shadowMap,projected + (vec2(1.0,0.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + projT.x; }\n"
" if (texture2D(shadowMap,projected + (vec2(0.0,0.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + 1.0; }\n"
" if (texture2D(shadowMap,projected + (vec2(-1.0,0.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + (1.0-projT.x); }\n"
" if (texture2D(shadowMap,projected + (vec2(0.0,1.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + projT.y; }\n"
" if (texture2D(shadowMap,projected + (vec2(-1.0,1.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + (1.0-projT.x)*projT.y; }\n"
" if (texture2D(shadowMap,projected + (vec2(1.0,1.0)/" + toString.str() + ")).r - zval > 0.0) { result = result + projT.x*projT.y; }\n"
" result /= 4.0;\n"
" }\n"
" }\n"
" return result;\n"
"}\n";
for (int i = 0; i < numSMT; i++)
{
toString.str("");
toString.clear();
toString << i;
fdec +=
"uniform sampler2D shadowMap" + toString.str() + ";\n"
"uniform mat4 shadowTransform" + toString.str() + ";\n";
}
// build the code for the lighting factors
std::string fimpl = "float factors[6];\n";
numSMT = 0;
for (int i = 0; i < 6; i++)
{
toString.str("");
toString.clear();
toString << i;
fimpl += " factors[" + toString.str() + "] = ";
if (i < numLights && this->ShadowTextureUnits[i] >= 0)
{
std::ostringstream toString2;
toString2 << numSMT;
fimpl += "calcShadow(vertexVC, shadowMap" +toString2.str() + ", shadowTransform" + toString2.str() + ");\n";
numSMT++;
}
else
{
fimpl += "1.0;\n";
}
}
// compute the factors then do the normal lighting
fimpl += "//VTK::Light::Impl\n";
this->FragmentDeclaration = fdec;
this->FragmentImplementation = fimpl;
}
// ----------------------------------------------------------------------------
void vtkShadowMapPass::BuildSpotLightIntensityMap()
{
......
......@@ -40,6 +40,7 @@
#include "vtkRenderingOpenGL2Module.h" // For export macro
#include "vtkRenderPass.h"
#include <vector> // STL Header
class vtkOpenGLRenderWindow;
class vtkInformationIntegerKey;
......@@ -53,8 +54,8 @@ class vtkTextureObject;
class vtkImplicitHalo;
class vtkSampleFunction;
class vtkShadowMapBakerPass;
class vtkInformationDoubleVectorKey;
class vtkInformationIntegerVectorKey;
class vtkInformationObjectBaseKey;
class vtkShaderProgram;
class VTKRENDERINGOPENGL2_EXPORT vtkShadowMapPass : public vtkRenderPass
{
......@@ -92,16 +93,32 @@ public:
virtual void SetOpaqueSequence(vtkRenderPass *opaqueSequence);
// Description:
// this key will contain the matricies for all the
// get the matricies for all the
// shadow maps.
static vtkInformationDoubleVectorKey *ShadowMapTransforms();
double *ShadowMapTransforms();
// Description:
// Key contaning the texture units for the shadow maps
// get the texture units for the shadow maps
// for each light. If a light does not cast a shadow
// it is set to -1
static vtkInformationIntegerVectorKey *ShadowMapTextures();
int *ShadowMapTextures();
// Description:
// this key will contain the shadow map pass
static vtkInformationObjectBaseKey *ShadowMapPass();
// Description:
// Get the shader code to compute light factors based
// on a mappers vertexVC variable
std::string GetFragmentDeclaration() {
return this->FragmentDeclaration; }
std::string GetFragmentImplementation() {
return this->FragmentImplementation; }
// Description:
// A mapper can call this to set the uniforms that this
// pass uses
void SetUniforms(vtkShaderProgram *program);
protected:
// Description:
......@@ -141,6 +158,13 @@ public:
vtkTimeStamp LastRenderTime;
// to store the shader code and settings
void vtkShadowMapPass::BuildShaderCode();
std::string FragmentDeclaration;
std::string FragmentImplementation;
std::vector<int> ShadowTextureUnits;
std::vector<double> ShadowTransforms;
private:
vtkShadowMapPass(const vtkShadowMapPass&); // Not implemented.
void operator=(const vtkShadowMapPass&); // Not implemented.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment