Jump to content

Custom material mask bit


photo

Recommended Posts

Hello,

I'm having some problem understanding how one can use a custom bit inside gbuffers material mask. I am using Unigine 2.13.0.1.

But first here is my problem:

I have some surfaces that are supposed to be emissive only on some portions. I know I have the emission pass, but cannot render the same geometry again but with different shader (way to expensive and would need a lot of refactoring), so I need to output the pixels that are supposed to be emissive from the same pass that I normally use to render the geometry (normal deferred rendering pass).

So:

-  1. I was thinking to do an additional rendering pass, an emission pass one (Unigine::Render::PASS_EMISSION inside an extern object), with a material on the entire screen (Material::renderScreen), and if a certain bit inside the material mask is set then output it as emissive (non zero) to the destination emission texture. 

- 2. So during normal geometry deferred rendering, I pick a "free" bit from gbuffer.material_mask and set it as either 1 (emissive) or 0 (non emissive). This is needed since I need to do the emissive pass only for my own geometry pixels (we also render other Unigine geometry in the scene, that I don't want to be emissive).

- 3. The material mask texture is then set as input texture for the emissive pass as described at 1.

Now the problem I have is that I don't know how to use the material mask. Looking at the shaders and Unigine source code I can see:

#define FREE_MATERIAL_MASK 0x00FFFFFF
#define RESERVED_MATERIAL_MASK 0xFF000000

So fine, I am supposed to be using some bit in the free part (first 8 bytes). But then the default written mask by all Unigine materials is:

#define DEFAULT_MATERIAL_MASK (FREE_MATERIAL_MASK | ...)

So the gbuffer is filled with all the free material mask bits already set. Ok, so then I thought, maybe using a certain bit means clearing it actually (not setting it). But then looking at the sky, it is clearing all the bits from the mask except reserved DOF and motion blur bits.

So now I am left with a final screen with the gbuffer. material_mask either with all free bits cleared (sky) or all set (the rest of the geometry). So cannot make a distinction. Unless I can use multiple bits and some sort of pattern of them to detect where is my emissive geometry.

So all boils down to: how one can use the Unigine gbuffer material mask for his own masking?

Kind Regards,
Adrian L.

Link to comment

Hi Adrian,

You should use free material mask bits, e.g. first 24 bits of material mask.
In your material add (for ULON materials)

Texture2DInt material_mask <type=gbuffer_material_mask>

And sample it like a regular int texture. For examples you can check out core/shaders/screen_space/dof/mask.frag :

int material_mask = TEXTURE_FETCH(TEX_MATERIAL_MASK, uv * s_viewport.xy).x;
OUT_COLOR *= float(checkMask(material_mask, DOF_BIT));


You need to define your own bit for readability like so:

#define SSR_BIT						1<<30



 

Link to comment

Hello and thank you for your response.

My material is the old format. But that's not the issue. The issue I have is that it seems that all the other Unigine materials write 1 in all free bits:

#define FREE_MATERIAL_MASK 0x00FFFFFF
#define DEFAULT_MATERIAL_MASK (FREE_MATERIAL_MASK | MATERIAL_MASK_SSAO_BIT | MATERIAL_MASK_SSR_BIT | MATERIAL_MASK_DOF_BIT | MATERIAL_MASK_MOTION_BLUR_BIT | MATERIAL_MASK_SHADOW_SHAFTS_BIT | MATERIAL_MASK_SHORELINE_WETNESS_BIT)

So everything that is Unigine solid mesh and renders on screen will set all the free bits to 1 (except the sky part). So for my own geometry that renders together with the other geometry I cannot use any of these bits (set it to indicate that the final pixel is affected by me).

To test that nothing is wrong with our engine integration, I've also loaded CityGenDemo in the browser and read the material mask with RenderDoc:

image.thumb.png.d4b10eca83cd1d7084c3efc1fdd3a9c5.png

So right clicking on material mask on any of the screen part occupied by terrain, billboards or meshes I've got the value DDFFFFFF (hexa) which means all the free bits set.

Right clicking on the sky part I've got:

image.thumb.png.e7cd1a8d9878bf36c4e5a07eba350211.png

so 1800000, which means only DOF_BIT and MOTION_BLUR_BIT are set (as the core\shaders\screen_space\fragment\clear_material_mask.frag is used for sky part).

So again, I need to ask, how am I supposed to use the free material mask bits - only my geometry to write to a certain bit, so I can indicate where my material is writing on screen? I cannot, since I don't know if I wrote the final bit or some other Unigine material wrote it.

I am using Unigine 2.13.0.1 and I have all the other details figured out (how to take a pointer of the gbuffer material mask and how to setup it on C++ side and how to read it and use checkMask in shaders), but I cannot rely on the material mask texture itself to have some bit reserved for my own usage. Isn't this the intended usage for it (to let it user defined materials pick bits for their own purposes)?

Regards,
Adrian L.

Link to comment

Hi,

please check material mask on your materials. By default they are all set to 0xFFFFFF

Here's a simple example using Scriptable Materials in 2.13

BaseMaterial material_mask <options_hidden=1 preview_hidden=1 var_prefix=var texture_prefix=tex>
{
	Texture2D screen_texture <type=procedural internal=true>
	Texture2DInt material_mask <type=gbuffer_material_mask>
	
	Color my_color = [0.5 0.5 0.5 1.0]
	
	Pass my_pass
	{
		Fragment =
		#{
			#include <core/shaders/common/fragment.h>
			
			#define MY_MASK_BIT 1 << 1
			
			MAIN_BEGIN(FRAGMENT_OUT, FRAGMENT_IN)
				
				float4 color = TEXTURE_BIAS_ZERO(tex_screen_texture, IN_UV);
				int mask = TEXTURE_FETCH(tex_material_mask, IN_UV * s_viewport.xy);
				
				OUT_COLOR = color * lerp(float4_one, var_my_color, checkMask(mask, MY_MASK_BIT));
			MAIN_END
		#}
	}
	
	Expression RENDER_CALLBACK_END_POST_MATERIALS =
	#{
		Texture screen_texture = engine.render_state.getScreenColorTexture();
		
		Texture source = engine.render.getTemporaryTexture(screen_texture);
		source.copy(screen_texture);
		
		setTexture("screen_texture", source);
		
		renderPassToTexture("my_pass", screen_texture);
		
		engine.render.releaseTemporaryTexture(source);
	#}
}


Attach it to your camera or globally in Scriptable Materials tab in Settings here:
image.png

Make a sphere and inherit default material. Then clear it's material mask to get a picture like this:
image.png
Notice how this sphere stands out on grayness of everything else.

Hope it helps!

Link to comment

Hello,

Ok, so then my question is: why all your core materials set the free bits as 1 (and not zero)? Wasn't these bits supposed to be left free so user custom shaders write to them? 

Will try to do as in your example above, and basically use zero for a custom free bit to indicate where I write with my material. But last time I've tried this, the sky was also set on zero on all these bits.

Kind regards,

Adrian

Edited by adrian.licuriceanu
Link to comment

Hello,

Ok, so using the reverse (considering the free bit as 1 by default and clearing with my own shaders only bit 22 to indicate where to put emissive pixels) kind of works as a mask. But then there is this problem:

The engine has the sky portion cleared (as described several times above) via:

	if(TEXTURE_LOAD(TEX_DEPTH, uv).r != 0)
		discard;
	
	OUT_COLOR = DOF_BIT | MOTION_BLUR_BIT;

in core\shaders\screen_space\fragment\clear_material_mask.frag. So this sets as zero all the material mask free bits for the sky part. And because the material mask (and all gbuffers for that matter) are never cleared by Unigine at the beginning of the frame, when I move the camera up and down, I can see my emissive pixels (put where the bit 22 is zero) also leaving a trail on the sky portion (probably due to the order of all the clears and renderings):

image.thumb.png.fac0db38ae5e70f6e46cca43ce4f55bf.png

If the sky also sets the free bits (as every other material in the engine), as:

	OUT_COLOR = DOF_BIT | MOTION_BLUR_BIT | FREE_MATERIAL_MASK;

Then everything is fine. 

So the question is: why the sky doesn't set the free bits of the material mask as 1 as everybody else? It is the exception and makes the entire system unusable .

Regards,
Adrian L.

Link to comment
On 9/20/2022 at 3:04 PM, adrian.licuriceanu said:

why all your core materials set the free bits as 1 (and not zero)? Wasn't these bits supposed to be left free so user custom shaders write to them? 

That was made so the user's material checking free mask for specific bit won't disable material completely but rather on the sky.
In our projects we clear all mask bits to 0 and assign them on demand.
 

1 hour ago, adrian.licuriceanu said:

The engine has the sky portion cleared (as described several times above)

We don't clear most of the buffer textures for performance reasons.
To exclude sky pixels you can copy this logic but don't forget about initializing depth texture in your material:

<texture source="current_depth"/>

 

Quote

why the sky doesn't set the free bits of the material mask as 1 as everybody else? It is the exception and makes the entire system unusable .

This is to distinguish sky and materials that write to material mask. To make this a little bit more usable clear material masks for all of your materials and set bits for each material separately.


I Hope this helps!

Link to comment
×
×
  • Create New...