像素化光照着色器

8
我已经为我的像素化iOS应用程序编写了一个GLSL着色器,以在Unity3D中使用。它有1个问题:
1)效果并不总是跟随月亮,并且 2)照明看起来不像像素化。
我稍微解释一下。该着色器旨在在月亮在其后面时对前景对象产生照明效果。我有一个精灵,通常显示为全黑色(如剪影),但当月球物体足够靠近它时,它会显示纹理的细节,就像这样:

enter image description here

实际的精灵(没有着色器)看起来像这样:

enter image description here

我这样做的原因是为了只使用一个纹理来制作光照贴图。但是,它存在两个问题:
1)当我靠近屏幕边缘时,光效不会完全跟随月亮。我不确定这是否与TEXCOORD1变量的错误使用有关。我制作了一个覆盖整个屏幕的精灵,以便您可以看到它如何不跟随月亮。这是我的测试场景中出现问题的图片。有一个全屏的带有黑色条纹和透明度的精灵,可以清楚地显示效果的位置。我想消除这种不同步,因为它使光线看起来不真实。

enter image description here

2) 产生的照明效果非常锐利-- 我认为,如果每个像素都像SpriteLamp中一样单独点亮会更好。我知道这与着色器中舍入片段坐标有关,但由于我从未真正知道我的着色器变量的值,因此我似乎无法正确地解决这个问题。

我可以对距离进行四舍五入和向下取整,但然后我会得到这个结果,它遵循了月球的距离,但不遵循原始精灵中的像素。虽然存在像素化,但我们最终得到的是这种奇怪的曲线跨越了本应只有一个像素的区域,如果你能理解我的意思的话...

enter image description here

我需要的更像是这样。您能看到原始纹理的每个像素都被点亮了吗?

enter image description here

这是着色器本身的链接: http://pastebin.com/0zbqrP57。它基本上是默认的Unity精灵着色器,但在SampleSpriteTexture函数的结尾添加了一些代码。
这是一个unitypackage的链接,您可以使用它来查看着色器的效果。只需在场景播放时尝试移动月亮即可。

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

我的问题:你有关于如何解决这些问题或者它们的解决方案吗?


2
我理解你的问题,但你没有提出具体的问题。你是想了解为什么会发生不同步吗?还是期望得到解决方法的建议?这里的确切目标是什么?请编辑。 - CosmicGiant
嗨,@AlmightyR,谢谢您的建议。我希望得到更多的建议和解决方案。我已经更新了问题描述。目标是实现问题2中的效果(因为这比当前设置看起来更好),并解决失步问题。 - Catlard
1
哇,它像魔法般地运行正常。谢谢你。 - user6517192
1
@Catlard:要实现像素化照明效果,你应该使用较低分辨率进行渲染,然后使用最近邻上采样。 - Yakov Galka
@ybungalobill 感谢您的建议 - 我进行了谷歌搜索,但实际上并没有弄清楚您建议我做什么。您有示例吗?或者更好的描述如何做到这一点?谢谢。 - Catlard
显示剩余3条评论
1个回答

2

更改

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

对于

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

需要修复月亮位置错误。

对于第二个问题,我想到了以下解决方案:

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);
}

我认为你可以放弃if语句和lerps,只需:
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;

但是在这种情况下,您应该在自己的设备上测试它,并检查它是否提高了性能。


第一个修复很好!你能解释一下为什么它不同吗?但是像素化的照明方案并不是我想要的。抱歉没有更具体地说明。我已经更新了问题。鞠躬 - Catlard
要明确一点,我知道我们为什么要摆脱条件语句,但是为什么IN.vertex和OUT.vertex不同呢?那里发生了什么?你看到我的更新了吗?如果你真的不理解,请告诉我。 - Catlard
我真的不知道为什么会有差异。即使你将 OUT.vertex = UnityObjectToClipPos(IN.vertex); 更改为 OUT.vertex = IN.vertex; 并且去掉 UnityPixelSnap(),它也无法正常工作。也许更有经验的人可以解释一下。你能再次上传 unitypackage 吗?我的月亮材质和/或精灵已经损坏了。 - Krajca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接