Trying to create a shader returning texel per pixel ratio

Hello there,

I’m currently working on some tooling related to performance check for a Unity project.
I must say my knowledge in computer graphics is limited for now, so please forgive me if my question looks somehow nooby!

Among other things, I would like to have a shader returns a texel per pixel ratio as a color lerp, something looking like that :

float4 final_color = lerp(float4(1,0,0,1), float4(0,1,0,1), saturate(texel_pixel_ratio));

This means that, I need to calculate the texel/pixel value.
So, here would be the thing :

  • if 1 texel corresponds to 1 pixel, texel_pixel_ratio = 1, pixel-perfect, display yellow
  • if 1 texel covers more than 1 pixel, texel_pixel_ratio < 1, lerp towards red
  • if 1 texel covers less than 1 pixel, texel_pixel_ratio > 1, lerp towards green

My problem lies in the following calculation: I want to know how many pixels on my screen are mapped to one particular texel of the displayed texture. So I can possibly calculate the ratio. Of course, I would like that shader to be screen-space based, meaning the color returned shall be different according the camera distance and orientation to the textured object (to be used in the Game View for example)
So if I’m not completly off, I need a screen-space texel size I can compare to a screen-space pixel size.
Within a shader, I know I can access the following :

float4 _MainTex_TexelSize; //gives me an absolute texel size (components x and y) based on texture width and heigth


- ```csharp
float4_ScreenParams; //gives the screen resolution (components x and y) and therefore the number of pixels on each x and y screen axis

There is also the question of mip levels : since using a tex2d sampler will automatically select the best mip, I know I should account for this but I’m not sure I can access the currently used mip level within a shader.

PS: I’ve come accross those resources, but I’m not sure how this applies to my question (I’m probably too inexperienced with shaders for now) :
Obtaining screen-space texel size? - Unity Forum
Question - How to get mip map level directly in shader? - Unity Forum
Calculate used mipmap level, ddx, ddy? - Unity Forum

Thanks in advance for those interested in this question :slight_smile:

What you want is the mip level.

A texture’s mip level is directly related to the texel to pixel ratio, but where +/- 1.0 mip level is 2^(mip level difference) texels per pixel. So a mip level of 0 is perfectly 1:1. A mip level of 1 is 2:1 texels to pixel, and -1 is 0.5 texels to pixel.

The ddx() and ddy() give you how much a value changes between the current pixel and the next* in the screen space horizontal and vertical direction respectively. So if you take the uv and multiply it by the texture dimensions, that’s the texel coordinate for that texture. And thus the ddx(uv * textureResolution) and ddy(uv * textureResolution) return the texels per pixel for that screen pixel. But since the mesh UVs might not be aligned with the screen, you need the float2 value. You could do max(length(ddx(uv * texRes), length(ddy(uv * texRes)), but I recommend using that mip map function in the last link as you’ll get a much more useful value range to use for your coloring.

float mipLevel = mip_map_level(uv * _MainTex_TexelSize.zw);
half4 col = half4(1 - saturate(mipLevel), 1 - saturate(-mipLevel), 0, 1);

* It’s not quite the value of the “current” pixel, or a difference between it and the “next”, but rather the difference along the x and y of that pixel quad. The way GPUs work, the screen is sliced up into a 2x2 pixel grid where each square 2x2 pixel group is called a “pixel quad”. This set of 4 pixels is the smallest number of pixels a GPU can render at one time, it’ll always render an entire pixel quad. The ddx() and ddy() values will actually be the same for all pixels within the pixel quad, or within each row / column of a pixel quad, depending on the graphics API. They do this explicitly for mip map calculations.

3 Likes

That’s a detailed and useful answer.
The code works also nicely for the view I was aiming at, many thanks to you.