Pixel-perfect shader in Unity ShaderLab
Asked Answered
P

4

12

In Unity, when writing shaders,

is it possible for the shader itself to "know" what the screen resolution is, and indeed for the shader to control single physical pixels?

I'm thinking only of the case of writing shaders for 2D objects (such as for UI use, or at any event with an ortho camera).

(Of course, normally to show a physical-pixel perfect PNG on screen, you merely have a say 400 pixel PNG, and you arrange scaling so that the shader, happens to be drawing to, precisely 400 physical pixels. What I'm wondering about is a shader that just draws, for example a physical-pixel perfect black line - it would have to "know" exactly where the physical-pixels are.)

Pigg answered 22/1, 2016 at 17:3 Comment(2)
If you look for 2D solution you can force the Canvas to be pixel-perfect.Unassailable
Hi Jerry, that really has absolutely no connection to what I'm talking about. Thanks.Pigg
G
7

There is a ShaderLab built-in value called _ScreenParams.

_ScreenParams.x is the screen width in pixels. _ScreenParams.y is the screen height in pixels.

Here's the documentation page: http://docs.unity3d.com/462/Documentation/Manual/SL-BuiltinValues.html

Gonzalo answered 29/1, 2016 at 2:20 Comment(1)
Whoa - that seems to be a critical tipPigg
E
5

I don't think this is going to happen. Your rendering is tied to current selected video mode and it doesn't even have to match your physical screen size (if that is what you mean by pixel-perfect).

The closest you are going to get with this is if you render at recommended resolution for your display device and use pixel shader to shade an entire screen. This way, one 'physical pixel' is going to be roughly equal to one actual rendered pixel. Other than that, it is impossible to associate physical (that is your display's) pixels to rendered ones.

This is unless, of course, I somehow misunderstood your intentions.

Embraceor answered 22/1, 2016 at 17:12 Comment(4)
Hi MM. Fascinating. TBC then, there's just no way to access "physical screen pixel count" from the shader then. (I've noticed folks often do this as a "trick" by having a helper script pass it in as a number, from outside.)Pigg
The problem is physical screen has very little to do with actual rendering which is carried out by your graphics card, which in turn knows about video mode, not actual display size.Embraceor
Gotchya. That explanation is a great help. Look, when looking at my ordinary Mac right now, the small orange square "Questions" at the top of this web page, is indeed rendered in a physical-pixel-perfect manner. (I just enlarged that and triple-checked that!) And Safari / the operating system does that on various screen sizes. What's the deal there?Pigg
Passing physical screen size as a constant to a shader is not a trick but a well-known and a pretty easy practice. It's even better if you calculate stuff you need for your shader in a c# script and pass that along instead of calculating constants based on screen size in shader.Intermission
N
4

is it possible for the shader itself to "know" what the screen resolution is

I don't think so.

and indeed for the shader to control single physical pixels?

Yes. Pixel shaders know what pixel they are drawing and can also sample other pixels.

Nicollenicolson answered 22/1, 2016 at 22:42 Comment(6)
Ahhhhhh .. so when you say they know "what pixel" they are drawing on ..... you mean that's certainly a PHYSICAL pixel? Is that right? there are so many layers of abstraction, it's difficult to understand these things if you're a non-expert.Pigg
So -- to clarify my question -- to be sure to be sure, these "pixel shaders" you mention, to clarify, one would actually WORK DIFFERENTLY if on a 1024 screen, when the same app is on a 1600 screen ... am I on the right track?Pigg
is it true that "fragment shader" is literally another word for "pixel shader" -- they two different terms for exactly the same thing? or, do I have it all wrong? thanks for this!!Pigg
It depends on what you mean by PHYSICAL pixel. If you mean (for example) the 1280x720 distinct addressable pixels, then yes the pixel shader knows which one it's drawing. If you're taking about the lower level hardware that physically makes up monitor, then the shader will only know that if the monitor is in its native mode.Nicollenicolson
The pixel shader should not operate differently for a different resolution screen. It will just have a different range of pixels thrown at it from the vertex shader. The vertex shader will behave differently depending on many things, including the screen resolution.Nicollenicolson
Pixel shader is from HLSL, and fragment shader is Cg. They are pretty much the same things, but it also implies which system you are using.Nicollenicolson
E
2

First of all, please define 'Pixel perfect' and 'Physical pixel'.

If by physical pixel you mean your display's pixel (monitor, laptop display, any other hardware you might use) then you are out of luck. Shaders don't operate on those, they operate on their own 'abstract pixels'.

You can think about it in this way: Your graphics are rendered in a picture with some configurable resolution (say 800x600 pixels). You can still display this picture on a 1920x1080 display in full screen no problem, it would look crappy though. This is what's happening with actual display and video card rendering. What determines the actual amount of rendered pixels is your video mode (picture's resolution in the above example). And physical pixels are your display's pixels. When rendering you can only operate on the first kind.

This leads us to a conclusion that when you render the graphics at the exact same resolution as your display's native resolution, you can safely say that you endeed render it as 'Physical Pixels'.

In unity, you can pass the renderer some external data (this might include your current screen resolution (for example as a Vector2, see this). However you most likely don't need any of this, since pixel shaders already operate on pixels (rendered pixels, determined by your current video mode). That means that if you use some resolution which is lesser than your native one, you most likely will not be able to render a single pixel.

Hope it helped.

Embraceor answered 3/2, 2016 at 9:36 Comment(4)
Hi MM, hmm, it's trivial to get the physical pixels of a display in native programming, and it is always available in Unity, too. HalpPlz is saying it indeed is available in ShaderLab! _ScreenParams.x ... which is great news.Pigg
BTW here on SO, to see all the edits of a question, just click the "edited..." link (just under the question tags to the right)Pigg
I am pretty sure that _ScreenParams.x is referring to the resolution defined by the Video Mode, not the actual display size.Embraceor
Right, it seems to be the "current render target width"Pigg

© 2022 - 2024 — McMap. All rights reserved.