How to sample depth texture in GLSL?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

How to sample depth texture in GLSL?

Post by Andrey01 »

I have a problem with sending and sampling a depth texture in GLSL fragment shader. I generate it in D16 color format, set it in the render target as the second parameter, then render and after send it in the fragment shader as sampler2D:

Code: Select all

video::ITexture* base_t = vdrv->addRenderTargetTexture(core::dimension2du(1024, 680), "BaseRT", video::ECF_A16B16G16R16F);
video::ITexture* depth_t = vdrv->addRenderTargetTexture(core::dimension2du(1024, 680), "DepthRT", video::ECF_D16);

// in while loop:
rt->setTexture(base_t, depth_t);
vdrv->setRenderTargetEx(rt, video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 0, 0, 0));

smgr->drawAll();

// in fragment shader:
uniform sampler2D mDepthTex;

void main(void)
{
vec2 depthTexCoords = gl_FragCoord.st / vec2(1024, 680); // to span [0, 1]
float depth = texture2D(mDepthTex, depthTexCoords).r; // the first component is supposed to be containing depth value

gl_FragColor = vec4(vec3(depth), 1.0); // that always output a white color independing on the distance to the rendered object
}
I'm not sure how to set a correct sampler type and use a correct texture function for that. I tried various variants: set it as 'sampler2D' and used 'texture2D(sampler2D, vec2)', then tried as 'sampler2DShadow' and then 'shadow2D(sampler2DShadow, vec3)' and also just 'texture(sampler2DShadow, vec3)' functions. None of those work properly. However, passing to 'mDepthTex' the color texture 'base_t' instead of 'depth_t it draws various colors depending on the camera orientation is what as expected. Maybe do I just set incorrect sampler type, texture function or something else?
CuteAlien
Admin
Posts: 9643
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to sample depth texture in GLSL?

Post by CuteAlien »

The depth texture is the target - not the source, so it's what you write to, not what you read. I googled around a bit and it seems if you want the current fragment depth value you can get that from gl_FragCoord.z
But note that this is not necessarily the final value which will be in your depth texture as later fragments can overwrite it. At this point you can't know the final result yet.
If you need the real result you have no other option but passing that texture as input in another stage.
And if you need it already in this stage and have no other option you will have to render the scene twice. Or maybe use some kind of deferred rendering (please look that up, I never did it myself).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

Re: How to sample depth texture in GLSL?

Post by Andrey01 »

Thanks for reply. I've just added an additional render pass (render to my own depth texture necessary objects and then pass it to the end shader to sample from that).
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

Re: How to sample depth texture in GLSL?

Post by Andrey01 »

Hmm, I thought now about multiple render targets. What if I have two textures (color and its depth) and I assign two outputs in gl_FragData, one for color, another one for depth? Will depth testing be implemented automatically also for depth texture? As I have two passes and in each of them I send the same geometry, it would be a good way to optimize it by using only one pass. And btw how do I set multiple render targets in Irrlicht, just create two IRenderTargets or in one IRenderTarget set two textures as cube surfaces?
CuteAlien
Admin
Posts: 9643
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to sample depth texture in GLSL?

Post by CuteAlien »

If you want to set custom depth values use gl_FragDepth, not gl_FragData. Thought I suppose in theory you could set a multi-render target and write gl_FragCoord.z into the second one with gl_FragData. But why not use the depth-texture you already have?

I don't know about your use case, but my feeling is that it won't be what you want. If you need the final depth data, you can't avoid a second render pass easily. The problem is that your fragment always only know it's own depth ( gl_FragCoord.z). It can't know the depths of fragments rendered later (which may be be above it) as those are not calculated yet.


You can optimize multiple passes by not using textures for first pass (unless you need them for alpha information which can affect depth as well). Or avoiding all expensive calculations in shaders in first pass (no light, etc). Or reducing texture switches, as all textures without alpha can usually be removed or replaced by one simple texture (texture switches tend to be expensive, geometry rendering without them can often be super fast).

And there is deferred shading. I'm not familiar enough with it to give you an introduction really, you have to look that up on the web (Wikipedia for example). But in short it it will write lot of information (not just depth) into textures to decouple geometry rendering from lighting. And that allows it to avoid rendering geometry several times. But it also comes with a bunch of problems.

Setting MRT's you create a single IRenderTarget and then set several textures. Just leave the cube surfaces array empty (which is the default parameter, so simply don't use 3rd parameter).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

Re: How to sample depth texture in GLSL?

Post by Andrey01 »

Hmm, the MRT feature doesn't work to me although queryFeature(video::EVDF_MULTIPLE_RENDER_TARGETS) reports true. I set core::array with two RT textures, both ones are color format A16B16G16R16F in IRenderTarget::setTexture() without the third parameter and then in the end of the fragment shader I assign two color outputs gl_FragData[0] and gl_FragData[1] as vec4 type. It just display a black screen. If I assign only in one of those outputs, e.g. only in gl_FragData[1] it doesn't change anything. However, if I pass only one texture in IRenderTarget::setTexture(), there will be output to the screen, but only in gl_FragData[0].
CuteAlien
Admin
Posts: 9643
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to sample depth texture in GLSL?

Post by CuteAlien »

Works here. Please make an example if it fails or I can't do anything.

Code: Select all

#include <irrlicht.h>

using namespace irr;

#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

int main()
{
	core::dimension2du screenDim(640, 480);
	IrrlichtDevice *device = createDevice(video::EDT_OPENGL, screenDim);

	if (!device)
		return 1;

	video::IVideoDriver* driver = device->getVideoDriver();

	video::IRenderTarget* rt = driver->addRenderTarget();
	video::ITexture* rtt1 = driver->addRenderTargetTexture(screenDim, io::path("rtt1"), video::ECF_A16B16G16R16F);
	video::ITexture* rtt2 = driver->addRenderTargetTexture(screenDim, io::path("rtt2"), video::ECF_A16B16G16R16F);
	video::ITexture* depth = driver->addRenderTargetTexture(screenDim, io::path("depth"), video::ECF_D32);
	core::array<video::ITexture*> textures;
	textures.push_back(rtt1);
	textures.push_back(rtt2);
	rt->setTexture(textures, depth);

	while(device->run())
	{
		driver->beginScene(true, true, video::SColor(255,100,101,140));

		// just so we see original which should show
		driver->draw2DRectangle(video::SColor(255, 255, 100, 100), core::recti(100, 100, 500, 200));

		// now render same into rendertarget
		driver->setRenderTargetEx(rt, video::ECBF_ALL, video::SColor(255,0,50,100));

		// draw same again, this time into render target
		driver->draw2DRectangle(video::SColor(255, 255, 100, 100), core::recti(100, 100, 500, 200));
		driver->setRenderTargetEx(0, video::ECBF_NONE);

		// draw rtt, but smaller
		driver->draw2DImage(rtt1, core::recti(0, 240, 320, 480), core::recti(0,0,640,480));
		driver->draw2DImage(rtt2, core::recti(320, 240, 640, 480), core::recti(0,0,640,480));

		driver->endScene();
	}

	device->closeDevice();
	device->drop();

	return 0;
}

IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

Re: How to sample depth texture in GLSL?

Post by Andrey01 »

Now works too to my wonder. The single reason which I can find is I initialized core::array wrong (when I added ITextures to there, I used direct [] operator, now I added it by push_back()), because actually my current code and the non-working code before are absolutely identical except that thing. Thanks for help.
CuteAlien
Admin
Posts: 9643
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to sample depth texture in GLSL?

Post by CuteAlien »

You can only use [] operator when the array already has the required size (either by calling set_used or using the constructor with the size argument).
But good it works now!
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply