Pixelated lighting shader
Asked Answered
L

1

8

I've written a GLSL shader for use in Unity3D with my pixelated iOS app. It has two ONE problems:

1) The effect doesn't always stay with the moon, and 2) the lighting doesn't look pixelated.

I'll explain a little. The shader is meant to cause a lighting effect on a foreground object when the moon is behind it. I have a sprite which is normally displayed as all black (like a silhouette), but when the moon object is close enough to it, it reveals the details of the texture, like so:

enter image description here

The actual sprite (without the shader) looks something like this:

enter image description here

The reason I am doing the effect this way is so that I can have a lightmap with only one texture. However, there are two problems with it:

1) As I get closer to the edge of the screen, the light effect doesn't follow the moon exactly. I'm not sure if this is related to my incorrect usage usage of the TEXCOORD1 variable. I've made a sprite that covers the whole screen so you can see how it doesn't follow the moon. Here's a picture of the problem in my test scene for the effect. There's a full-screen sprite with black stripes and alpha to show exactly where the effect is at all times. I want to get rid of this desync, because it makes the lighting look unrealistic.

enter image description here

2) The lighting effect caused is very sharp -- It would look better, I think, if each pixel was lit individually, as in SpriteLamp. I know it has to do with rounding the fragment coordinates in the shader, but since I never really know what the values of variables are in my shader, I can't seem to get this to work correctly.

I can round and floor the distance, but then I get this, which is obeying the distance from the moon, but not obeying the pixels in the original sprite. There is pixelation, but we end up with this weird curve across what should be just one pixel, if you catch my meaning...

enter image description here

What I'm looking for is more like this. See how the individual pixels of the original texture is lit?

enter image description here

Here's a link to the shader itself: http://pastebin.com/0zbqrP57. It's the default unity sprite shader, mostly, but with some code added in at the end of the SampleSpriteTexture function.

Here's the link to a unitypackage that you can use to look at the shader in action. Just try moving the moon around while the scene is playing.

https://drive.google.com/open?id=0BxCQjUHiAAQWZGpPZ3R2SExTcXc

MY QUESTION: Do you have any advice on how to solve these problems, or solutions to them?

Leapfrog answered 27/9, 2016 at 4:9 Comment(8)
I understand your problem, but you didn't make a specific question about it. Are you trying to understand why the desync happens? Expecting suggestions on workarounds? What exactly is the objective here? Please edit.Venereal
Hi, @AlmightyR, thanks for the suggestion. I am expecting suggestions and solutions. I've updated the question. The goal is to implement the effect in problem #2 (as it will look better than the current setup), and solve the desync problem.Leapfrog
wow it works like a charm . thank youVanwinkle
Haha, enjoy your broken shader! Come back when it's fixed.Leapfrog
@Catlard: to achieve pixelated lighting you should render at lower resolution and then upsample with nearest-neighbor.Snowberry
@ybungalobill Thanks for the advice -- I did a google search, but couldn't really figure out what it is that you're advising me to do. Do you have an example? Or a better description of how to do it? Thanks.Leapfrog
@Krajca Yes, it does look better. Sorry, been taking care of the baby, so I haven't gotten a chance to write back to you. Will do so later today.Leapfrog
@Leapfrog No problem, I just saw that you edited your question without response and thought that you overlook my response. Sorry for nagging.Bruckner
B
2

Changing

OUT.worldSpacePosition = mul(_Object2World, OUT.vertex);

for

OUT.worldSpacePosition = mul(_Object2World, IN.vertex);

should fix moon misplacement.

For second problem I came up with this:

aS = floor(aS * 100) / 100;
bS = floor(bS * 100) / 100;
float dist = sqrt((aS * aS) + (bS * bS));
float percentClose = 1 - (dist / _LightStrength);
float rounded = floor(percentClose * 10) / 10;

if (color.r + color.g + color.b > 0) {
    color.r = lerp(0, color.r, rounded);
    color.g = lerp(0, color.g, rounded);
    color.b = lerp(0, color.b, rounded);
}

I think you can drop if statement and lerps to just:

aS = floor(aS * 100) / 100;
bS = floor(bS * 100) / 100;
float dist = sqrt((aS * aS) + (bS * bS));
float percentClose = 1 - (dist / _LightStrength);
float rounded = floor(percentClose * 10) / 10;
color.rgb *= rounded;

But in this case you should test it on your end device and check if it improves performance.

Bruckner answered 30/9, 2016 at 2:56 Comment(3)
The first fix is great! Can you explain why it's different? But the pixelated lighting scheme isn't really what I was looking for. Sorry for not being more specific. I've updated the question. bowsLeapfrog
To be clear, I understand how/why we're getting rid of the conditionals, but why is IN.vertex different than OUT.vertex? What's going on there? Did you see my update? Let me know if you don't really understand.Leapfrog
I really don't know why it's different. Even if you change OUT.vertex = UnityObjectToClipPos(IN.vertex); to OUT.vertex = IN.vertex; and get rid of UnityPixelSnap() it will not work properly. Maybe someone more experienced could explain this. Can you upload unitypackage again? I have broken moon material and/or sprite.Bruckner

© 2022 - 2024 — McMap. All rights reserved.