Screen-position aligned Sphere Mask?

So I dunno if this is possible, but basically what I want to do is make a function that maps a sphere mask at the center of my screen, so that I can use it to mask out the opacity of a masked material, so that whenever my player (which, with the way my camera follows the player, is always on the center of the screen) walks behind certain objects, those objects will have a subtractive opacity mask, effectively culling the pixels blocking my view of my player. I’m using this so I can see my player whenever they walk inside a house or something, as I have an overhead camera following the player that doesn’t use collision tests to shorten the springarm target arm length.

Thanks for any insight guys and gals!

first approach would be to just feed the screen UVs into a sphere texture or make a sphere mask based on screen UVs in your objects material.

depending on your project you will run into issues with that though. the most obvious one being that objects will start to become invisible if the player is standing in front of them as well. can be fixed by adding the playerposition into the equation. the specific solution depends on things your camera can do. does it rotate around the player or is it always fixed?

The camera can rotate around the player, but the player is fixed at the center of the screen, and the camera is always above, pointing down at the player, and only rotates along the Z axis. (yaw rotation.) I’d ideally only be setting up this masking function on object materials that could be getting in the way of the camera seeing the player, i.e. buildings mostly. The major problem I see happening is the change in shadow behavior unless I use baked lighting, but that’s a whole different issue and I’ll cross that bridge when I get to it.

Is there any screen-space math I could do to ensure that regardless of the aspect ratio/resolution, that the circle mapped to screen uvs would always be a circle? As an example if I make a texture planed for 5:4 aspect ratio, if I use the same texture on a system using 16:9 aspect ratio, it’ll appear to be stretched out.

Thanks for your help! :slight_smile:

I used a square gradient instead of a circle, I can deal with a square frame being wide screen instead, at least for now. Thank you so much! :slight_smile:

So, say I were wanting to use a radial gradient, is there a solid way to get the screen resolution and scale the X ratio to compensate for aspect ratios so that the circle is always circular? If I use a screenposition node on the radial gradient function on a 16:9 screen, it stretches the gradient across the screen, as it technically should, but I’d like to compensate for that aspect ratio and others and make it stay at a 1:1 scale if possible.

Sure. you Just do

UVScale.x = Resolution.x * max(Resolution.x / Resolution.y, 1)
UVScale.y = Resolution.y * max(Resolution.y / Resolution.x, 1).

then you should just multiply the screen UVs by UVScale. the above should handle both cases if either X or Y is smaller. It will add extra padding to fit the smaller dimension rather than oversample for the smaller direction but you can flip it easily.

So I’m trying to recreate your equation but I’m having trouble finding the right nodes to use, particularly with splitting up the UV channels, would using a breakoutfloat2components node work for splitting UV channels?

Yup, its the same thing as using two component mask nodes, that function just contains them inside.

Try placing the ScreenPosition node and using that. if it doesn’t align correctly by default, try selecting the 2nd option in the drop down, I think its called viewportsize or viewportresolution or something.

I also forgot that you will have to subtract half of the difference in scale. so if X was multiplied by 2, it needs to offset by 1/2 first. I will be back later and I can try making an example using nodes if you are still messing with it.

So I tried structuring it, but I think I may have confused myself a bit on the structure. Here’s an image of what I have:


I’m getting a weird ellipses mask that expands outwards at a crooked angle, like this:

The screen position is the position you do the final multiply on, but you should be using ScreenResolution as the Resolution input. Will edit this post with an example in a few mins after my editor loads.

Here is the corrected version for just a version where x>y for simplicity. There was an extra multiply in my first example and I forgot to mention an offset of 0.5 (shame, shame)

UVScale.x = max(ScreenResolution.x / ScreenResolution.y, 1)
UVScale.y = 1

ScreenPositon *= UVScale;
ScreenPosition += float2(UVScale.x * 0.5 + 0.5, 0);

The bullseye will remain centered on the screen even while resizing the viewport in the editor with this setup. Just make sure to set screenposition to use viewportUVs.

2 Likes

Thank you so so much, that works so perfectly! One last question, is there a texture setting I can put in place to stop a texture from tiling? I’m using a radial gradient texture and I can control the size of the mask, but it appears to be tiled, so there are additional circles appearing in line with my center-positioned texture.

Again thank you very much for your help so far, it almost seems wrong to ask for anything else haha.

There should be a texture sampling mode called Clamped if you expand all the sections in the texture asset. You will likely have to recompile your material for it to take effect which I believe started being required when Shared:Wrap settings were added.

Awesome, that worked like a charm, thanks so much for all your help!

One last question, I’m using this setup in a top-down game to allow for the player to see their character when they go inside a house, but obviously masking out parts of the material this way lets outside light in. Is there a way to disable masked-shadows and have just the base geometry cast shadows instead?

Thanks so much again for all your help!

You would need to duplicate the house or use simplified roof shell geo and set it to hidden in game and also set it to ‘cast hidden shadows’. maybe require placing just beneat the actual roof surface to avoid conflicting with the visible roof before the cut out.

What if I set the materials on the inner walls to something separate (since inner wall normals would always be facing away from the camera when I’m trying to look in the house with the walls obstructing my view of the player character anyway) would they still cast shadows even though I wouldn’t actually be seeing the geometry since the normals would be facing away from me?

yea you could set cast 2 sided shadows on that mesh and try that.