ok, forget about math above, here's the code:
decal.vert
Code: Select all
uniform vec3 VertexFarLeftUp;
varying vec4 ScreenPos;
varying vec3 FarLeftUp;
varying float FarRightUpX;
varying float FarLeftDownY;
void main()
{
ScreenPos = ftransform();
gl_Position = ScreenPos;
FarLeftUp = VertexFarLeftUp;
FarLeftDownY = -FarLeftUp.y;
FarRightUpX = -FarLeftUp.x;
}
decal.frag
Code: Select all
uniform sampler2D firstPassTexture;
uniform sampler2D decalTexture;
uniform mat4 InvWorldView;
varying vec4 ScreenPos;
varying vec3 FarLeftUp;
varying float FarRightUpX;
varying float FarLeftDownY;
void main()
{
vec4 projCoord = ScreenPos / ScreenPos.w;
projCoord += vec4(1.0);
projCoord *= 0.5;
projCoord.xy = clamp(projCoord.xy, 0.001, 0.999);
//get depth
float vDepth = texture2D(firstPassTexture, projCoord.xy).a;
//reconstruct view pixel position
vec3 vProjPos = vec3(mix(FarLeftUp.x, FarRightUpX, projCoord.x),
mix(FarLeftDownY, FarLeftUp.y, projCoord.y),
FarLeftUp.z);
vec3 scenePosView = vec3(vProjPos * vDepth);
vec4 position = InvWorldView * vec4(scenePosView,1.0);
vec2 uv = position.xy;
uv += 0.5;
gl_FragColor = texture2D(decalTexture, uv);
}
decal shader callback
Code: Select all
class CDecalCallback : public IShaderConstantSetCallBack
{
public:
CDecalCallback(IEngineDevice *device)
{
m_pDevice = device;
}
virtual void OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData)
{
int tex0 = 0;
int tex1 = 1;
services->setPixelShaderConstant("firstPassTexture", (const float*)&tex0, 1);
services->setPixelShaderConstant("decalTexture", (const float*)&tex1, 1);
irr::scene::ICameraSceneNode* cam = m_pDevice->getSceneManager()->getActiveCamera();
irr::core::matrix4 viewMat = m_pDevice->getVideoDriver()->getTransform(ETS_VIEW);
irr::core::matrix4 projMat = m_pDevice->getVideoDriver()->getTransform(ETS_PROJECTION);
irr::core::vector3df farLeftUp= cam->getViewFrustum()->getFarLeftUp();
viewMat.transformVect(farLeftUp);
services->setVertexShaderConstant("VertexFarLeftUp", (irr::f32*)&farLeftUp, 3);
core::matrix4 worldViewProj(m_pDevice->getVideoDriver()->getTransform(video::ETS_PROJECTION));
worldViewProj *= m_pDevice->getVideoDriver()->getTransform(video::ETS_VIEW);
worldViewProj *= m_pDevice->getVideoDriver()->getTransform(video::ETS_WORLD);
core::matrix4 finalMat(worldViewProj.getTransposed());
matrix4 invFinalMat;
finalMat.getInverse(invFinalMat);
services->setPixelShaderConstant("InvWorldView", invFinalMat.pointer(), 16);
}
private:
IEngineDevice *m_pDevice;
};
example usage:
Code: Select all
ISceneNode *DecalBox;
s32 Decal;
Decal = driver->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles(
"./data/shaders/decal.vert", "main", EVST_VS_1_1,
"./data/shaders/decal.frag", "main", EPST_PS_1_1,
new CDecalCallback(device),
EMT_TRANSPARENT_ALPHA_CHANNEL);
//must be unit cube
DecalBox = device->getSceneManager()->addCubeSceneNode(1.0f);
DecalBox->setMaterialFlag(irr::video::EMF_BACK_FACE_CULLING, false);
DecalBox->setMaterialFlag(irr::video::EMF_FRONT_FACE_CULLING, true);
DecalBox->setMaterialType((E_MATERIAL_TYPE)Decal);
//set texture containing depth
DecalBox->getMaterial(0).setTexture(0, firstPass);
//set decal texture
DecalBox->getMaterial(0).setTexture(1, decalTexture);
result:
(stretching while I look around)
result when I remove line
Code: Select all
worldViewProj *= m_pDevice->getVideoDriver()->getTransform(video::ETS_VIEW);
from callback code. I know it's bad idea but take a look now:
looking good, BUT as expected due missing view inverse matrix, decal keep following me while I look around (but follow geometry "under the decal" - it's good!)
any hints how to fix this?
I've tried many things around changing order of: making inverse matrix and doing transpose but no success