I've played with postprocessing shaders a bit. Now I want to share my results...
The first one is a full screen glow effect. There is nothing special about the shader itself. But there my approach is slightly different.
In most articles about glow/blur you should render your scene twice, once for the glow map and second time for the color map. Because my scenes are complex, it's not possible to render them twice. So, I rendered it to al large texture and created a smaller one from this large one.
Here is some code for init stuff:
Code: Select all
CScreenQuadSceneNode *screenQuadNode[3];
ITexture* rtt[3];
rtt[0] = driver->addRenderTargetTexture(dimension2d<u32>(2048, 1024), "RTT0", ECF_A8R8G8B8);
rtt[1] = driver->addRenderTargetTexture(dimension2d<u32>(512, 512), "RTT1", ECF_A8R8G8B8);
rtt[2] = driver->addRenderTargetTexture(dimension2d<u32>(512, 512), "RTT2", ECF_A8R8G8B8);
screenQuadNode[0] = new CScreenQuadSceneNode(smgr->getRootSceneNode(), smgr, -1);
screenQuadNode[0]->getMaterial(0).MaterialType = EMT_SOLID;
screenQuadNode[0]->getMaterial(0).setTexture(0, rtt[0]);
screenQuadNode[0]->flipHorizontal();
screenQuadNode[1] = new CScreenQuadSceneNode(smgr->getRootSceneNode(), smgr, -1);
screenQuadNode[1]->getMaterial(0).MaterialType = (E_MATERIAL_TYPE)shader->getShaderMaterial(SShader::GlowShader1);
screenQuadNode[1]->getMaterial(0).setTexture(0, rtt[1]);
screenQuadNode[2] = new CScreenQuadSceneNode(smgr->getRootSceneNode(), smgr, -1);
screenQuadNode[2]->getMaterial(0).MaterialType = (E_MATERIAL_TYPE)shader->getShaderMaterial(SShader::GlowShader2);
screenQuadNode[2]->getMaterial(0).setTexture(0, rtt[0]);
screenQuadNode[2]->getMaterial(0).setTexture(1, rtt[2]);
In each frame I render the scene to rtt[0], create a smaller version in rtt[1], do the horizontal blur into rtt[2] and do the vertical blur and the blending into the frame buffer.
Code: Select all
/* draw the complete scene to a large rtt */
driver->setRenderTarget(rtt[0], true, true, SColor(0,0,0,0));
skyBox->setVisible(false);
smgr->drawAll();
if (pp_glowOn)
{
/* now copy the large rtt to a smaller one */
driver->setRenderTarget(rtt[1], false, false, SColor(0,0,0,0));
screenQuadNode[0]->render();
/* calculate the glow effect into the third rtt (based on the second one) */
driver->setRenderTarget(rtt[2], false, false, SColor(0,0,0,0));
screenQuadNode[1]->render();
}
else
driver->setRenderTarget(rtt[2], true, false, SColor(0,0,0,0));
/* and finally draw the base rtt + the glow rtt into the frame buffer */
driver->setRenderTarget(ERT_FRAME_BUFFER, false, false, SColor(0,0,0,0));
skyBox->setVisible(true);
smgr->drawSkyBox();
screenQuadNode[2]->render();
The base image looks like this:
With the glow effect (look at the engines):
GlowShader 1 (Vertex, glsl)
Code: Select all
varying vec2 Texcoord;
void main()
{
gl_Position = ftransform();
Texcoord = gl_MultiTexCoord0.xy;
}
Code: Select all
uniform sampler2D colorMap;
varying vec2 Texcoord;
const int gaussRadius = 15;
const int gaussRadiusHalf = 7;
float gaussFilter[gaussRadius] = float[gaussRadius](
0.001691,0.005779,0.016346,0.038269,0.074163,0.118968,0.157970,0.173629,0.157970,0.118968,
0.074163,0.038269,0.016346,0.005779,0.001691);
const vec2 uShift = vec2(1.0/512.0, 0.0);
void main()
{
vec3 color = vec3(0.0, 0.0, 0.0);
vec2 locTextCoord = Texcoord - gaussRadiusHalf*uShift;
for (int i=0; i<gaussRadius; ++i)
{
vec4 baseCol = texture2D(colorMap, locTextCoord);
if (baseCol.r + baseCol.g + baseCol.b > 0.7)
color += gaussFilter[i] * baseCol.xyz;
locTextCoord += uShift;
}
gl_FragColor = vec4(color,1.0);
}
Code: Select all
varying vec2 Texcoord1;
varying vec2 Texcoord2;
void main()
{
gl_Position = ftransform();
Texcoord1 = gl_MultiTexCoord0.xy;
Texcoord2 = gl_MultiTexCoord1.xy;
}
Code: Select all
uniform sampler2D colorMap;
uniform sampler2D glowMap;
varying vec2 Texcoord1;
varying vec2 Texcoord2;
const int gaussRadius = 15;
const int gaussRadiusHalf = 7;
float gaussFilter[gaussRadius] = float[gaussRadius](
0.001691,0.005779,0.016346,0.038269,0.074163,0.118968,0.157970,0.173629,0.157970,0.118968,
0.074163,0.038269,0.016346,0.005779,0.001691);
const vec2 uShift = vec2(0.0, 1.0/512.0);
void main()
{
vec4 baseCol = texture2D(colorMap, Texcoord1);
vec3 glowCol = vec3(0.0, 0.0, 0.0);
vec2 locTextCoord = Texcoord2 - gaussRadiusHalf*uShift;
for (int i=0; i<gaussRadius; ++i)
{
glowCol += gaussFilter[i] * texture2D(glowMap, locTextCoord).xyz;
locTextCoord += uShift;
}
if ((baseCol.r == 0) && (baseCol.g == 0) && (baseCol.b == 0))
gl_FragColor = vec4(glowCol, 0.4);
else
gl_FragColor = baseCol + vec4(glowCol, 0.0);
}
-------------------------------------------------------------------------------------------------------
The second effect is much more a shader effect. It's some kind of volume light. I have a directional light in the scene and transform the vector into a texture coordinate.
Code: Select all
void SWorld::getCamStuff(ICameraSceneNode *cam)
{
vector3df view = cam->getTarget() - cam->getPosition();
view.normalize();
vector3df light = MAIN_LIGHT_DIR_C;
light.normalize();
f32 a = view.dotProduct(light);
vector3df sl = light - view * a;
if (abs_(a) < 0.1)
sl *= 20000.0/0.1; // this 20000.0 is my 'far' clipping plane
else
sl *= 20000.0/abs_(a);
const SViewFrustum *frustum = cam->getViewFrustum();
vector3df upVect = frustum->getFarLeftUp() - frustum->getFarLeftDown();
vector3df rightVect = frustum->getFarRightDown() - frustum->getFarLeftDown();
shader->calcLVect.X = 0.5f+rightVect.dotProduct(sl) / rightVect.dotProduct(rightVect);
shader->calcLVect.Y = 0.5f+upVect.dotProduct(sl) / upVect.dotProduct(upVect);
}
Code: Select all
/* draw the complete scene to a large rtt */
driver->setRenderTarget(rtt[0], true, true, SColor(0,0,0,0));
skyBox->setVisible(false);
smgr->drawAll();
if (pp_rayOn)
{
/* now copy the large rtt to a smaller one */
driver->setRenderTarget(rtt[1], false, false, SColor(0,0,0,0));
screenQuadNode[0]->render();
/* do the ray stuff */
driver->setRenderTarget(rtt[2], false, false, SColor(0,0,0,0));
screenQuadNode[1]->render();
}
else
driver->setRenderTarget(rtt[2], true, false, SColor(0,0,0,0));
/* and finally draw the base rtt + the glow rtt into the frame buffer */
driver->setRenderTarget(ERT_FRAME_BUFFER, false, false, SColor(0,0,0,0));
skyBox->setVisible(true);
smgr->drawSkyBox();
screenQuadNode[2]->render();
Code: Select all
rtt[0] = driver->addRenderTargetTexture(dimension2d<u32>(2048, 1024), "RTT0", ECF_A8R8G8B8);
rtt[1] = driver->addRenderTargetTexture(dimension2d<u32>(512, 512), "RTT1", ECF_A8R8G8B8);
rtt[2] = driver->addRenderTargetTexture(dimension2d<u32>(512, 512), "RTT2", ECF_A8R8G8B8);
screenQuadNode[0] = new CScreenQuadSceneNode(smgr->getRootSceneNode(), smgr, -1);
screenQuadNode[0]->getMaterial(0).MaterialType = EMT_SOLID;
screenQuadNode[0]->getMaterial(0).setTexture(0, rtt[0]);
screenQuadNode[0]->flipHorizontal();
screenQuadNode[1] = new CScreenQuadSceneNode(smgr->getRootSceneNode(), smgr, -1);
screenQuadNode[1]->getMaterial(0).MaterialType = (E_MATERIAL_TYPE)shader->getShaderMaterial(SShader::RayShader);
screenQuadNode[1]->getMaterial(0).setTexture(0, rtt[1]);
screenQuadNode[2] = new CScreenQuadSceneNode(smgr->getRootSceneNode(), smgr, -1);
screenQuadNode[2]->getMaterial(0).MaterialType = (E_MATERIAL_TYPE)shader->getShaderMaterial(SShader::BlendShader);
screenQuadNode[2]->getMaterial(0).setTexture(0, rtt[0]);
screenQuadNode[2]->getMaterial(0).setTexture(1, rtt[2]);
screenQuadNode[2]->getMaterial(0).BlendOperation = EBO_ADD;
The ray shader (vertex glsl):
Code: Select all
varying vec2 Texcoord;
void main()
{
gl_Position = ftransform();
Texcoord = gl_MultiTexCoord0.xy;
}
Code: Select all
uniform sampler2D colorMap;
uniform vec4 fogColor;
uniform vec2 lPos;
varying vec2 Texcoord;
void main()
{
const float texSize=512.0;
int cnt = 0;
vec2 uShift = Texcoord - lPos;
float len = length(uShift) * texSize;
uShift = uShift / len;
const float ofs = 0.5/texSize;
vec2 locTextCoord = Texcoord;
while ((locTextCoord.x > ofs) && (locTextCoord.y > ofs) && (locTextCoord.x < 1.0-ofs) && (locTextCoord.y < 1.0-ofs) && (len > 0.0))
{
vec4 baseCol = texture2D(colorMap, locTextCoord);
if (baseCol.r + baseCol.g + baseCol.b > 0.0)
++cnt;
locTextCoord -= uShift;
len = len - 1.0;
}
float value;
if (cnt == 0)
value = 0.05;
else
value = clamp(0.05 - 0.0007*cnt, 0.0, 0.05);
gl_FragColor = vec4(fogColor.rgb, value);
}
If you have any questions, post them here or send me a PM.
And have fun with shaders...