Opengl es 当通过计算到边的最近距离来渲染内部阴影时,为什么边之间存在灯光区域?

Opengl es 当通过计算到边的最近距离来渲染内部阴影时,为什么边之间存在灯光区域?,opengl-es,glsl,opengl-es-2.0,glsles,Opengl Es,Glsl,Opengl Es 2.0,Glsles,我通过计算每个像素到边缘的最近距离来渲染内部阴影(与内部辉光的想法相同,但暗而不是光)。这是在片段着色器中通过从顶点着色器插值顶点位置(使用variable),通过统一数组传递形状的边点,并通过对每条边运行点到线段距离计算来计算最近距离来完成的 以下是片段着色器: precision mediump float; uniform mediump sampler2D uBaseSampler; uniform mediump vec2 uVerts[11]; varying mediump vec

我通过计算每个像素到边缘的最近距离来渲染内部阴影(与内部辉光的想法相同,但暗而不是光)。这是在片段着色器中通过从顶点着色器插值顶点位置(使用
variable
),通过统一数组传递形状的边点,并通过对每条边运行点到线段距离计算来计算最近距离来完成的

以下是片段着色器:

precision mediump float;
uniform mediump sampler2D uBaseSampler;
uniform mediump vec2 uVerts[11];
varying mediump vec2 vTexCoord;
varying mediump vec4 vPosition;
float distanceSq(mediump vec2 a, mediump vec2 b)
{
    mediump vec2 c = b - a;
    return dot(c, c);
}
float distSqFromLineSegment(mediump vec2 p, mediump vec2 a, mediump vec2 b)
{
    float lenSq = distanceSq(a, b);
    /*if (lenSq == 0.0) return distanceSq(p, a);*/
    float t = dot(p - a, b - a) / lenSq;
    if (t < 0.0) return distanceSq(p, a);
    else if (t > 1.0) return distanceSq(p, b);
    mediump vec2 proj = a + t * (b - a);
    return distanceSq(p, proj);
}
void main()
{
    float nearestDistSq = 1e3;
    for (lowp int i = 0; i < 10; ++i)
    {
        lowp int j = i + 1;
        float distSq = distSqFromLineSegment(vPosition.xy, uVerts[i], uVerts[j]);
        nearestDistSq = min(nearestDistSq, sqrt(distSq));
    }
    float nearestDist = nearestDistSq;
    float coef = nearestDist;
    lowp vec4 frag = texture2D(uBaseSampler, vTexCoord);
    gl_FragColor = vec4(frag.xyz * coef, 1.0);
}
precision mediump float;
均匀中泵取样器;
均匀介质矢量2 uVerts[11];
变化的mediump vec2 vTexCoord;
改变介质矢量位置;
浮动距离SQ(mediump vec2 a、mediump vec2 b)
{
mediump vec2 c=b-a;
返回点(c,c);
}
浮点距离SQFromLineSegment(mediump vec2 p、mediump vec2 a、mediump vec2 b)
{
float lenSq=距离sq(a,b);
/*如果(lenSq==0.0)返回距离sq(p,a)*/
浮动t=点(p-a,b-a)/lenSq;
if(t<0.0)返回距离sq(p,a);
如果(t>1.0)返回距离sq(p,b);
mediump vec2项目=a+t*(b-a);
返回距离sq(p,proj);
}
void main()
{
最近距离的浮动sq=1e3;
对于(低积分i=0;i<10;++i)
{
低内点j=i+1;
float distSq=distsqfromslinesegment(vPosition.xy,uVerts[i],uVerts[j]);
NEARESTDISSQ=最小值(NEARESTDISSQ,sqrt(DISSQ));
}
float nearestDist=nearestDistSq;
浮动系数=最近距离;
lowp vec4 frag=纹理2d(uBaseSampler,vTexCoord);
gl_FragColor=vec4(frag.xyz*coef,1.0);
}
以下是仅基于边1计算内部阴影时的外观:

以下是仅基于边2计算内部阴影时的外观:

请注意,两条边的内部阴影是如何分别正确的

现在,以下是基于两条边计算内部阴影时的外观:

注意边缘之间的内部亮度?作为参考,在基于所有边计算内部阴影时,这里有一个类似的结果:

当单独查看边1和边2生成的内部阴影时,看起来内部亮度不会通过同时分解两条边而形成。是什么引起的?沿亮度方向的点的距离不应大于其相邻点的距离,因为我正在计算与所有边的最小距离

有什么想法吗

更新:

根据一些早期的答案,我的问题似乎是我实现了一个“变暗”算法,以这种方式组合两个渐变会在我的截图中产生副作用。例如,如果您拍摄我的前两个屏幕截图,在图像编辑器中覆盖它们,并将第二层设置为“变暗”混合模式,您将获得我的第三个屏幕截图

我真正想要的是某种乘法。如果我在图像编辑器中使用“倍增”混合模式,我会获得所需的外观:

我将如何实现这一点?看起来我必须为每条边独立计算内部阴影,然后将所有系数相乘,而不是根据最近的边计算一个系数

更新2:


实现乘法混合模式会导致形状顶点周围的区域变暗。结果比我原来的版本更糟。我决定坚持使用原始版本,因为它快速、正确,并且通过将系数缩放到0.8-1.0(而不是0.0-1.0)左右,将不希望的副作用降至最低。我也接受了引导我走上这条道路的答案。

这张照片没有问题。。。OpenGL所绘制的正是您所要求的,即与边缘距离相关的亮度。距离不是平滑函数,所以你的眼睛看到的边缘距离函数的导数突然改变

你可以自己测试一下。打开一个图像编辑程序,如Gimp或Photoshop或其他任何东西,并制作两个线性渐变。对于第二个渐变,选择“变暗”作为渐变的合成模式。我得到了以下图像:

你可以看到这里有一条类似的45度线


如果你想去除锐利的边缘,你必须做更多的事情,比如模糊结果。距离场通常会有尖锐的边缘。

这并没有帮助我达到预期的结果,但它确实帮助我理解为什么我会得到这样的结果。你完全正确,我基本上实现了错误的混合模式——看起来我需要实现乘法混合模式。我已经用这些附加信息更新了我的问题。谢谢所以,我最终实现了乘法混合模式,它实际上看起来很糟糕。它会导致形状顶点周围出现较暗的圆形区域,因为来自两条边的阴影会相乘。然而,它的折痕看起来更好。我会将你的答案标记为正确答案,因为你完全正确,我原来的算法没有任何错误。你可以使用模糊,这是一种相当传统的处理方法。(1) 将形状渲染成纹理(2)使用片段着色器模糊纹理。这是真的,但对于低端设备来说这相当昂贵。我宁愿在片段着色器中完成尽可能多的工作,而不必求助于后期处理。后期处理也会导致类似这样的问题,我们如何在不越过边缘的情况下模糊多个形状?如果你想要传统阴影,你需要能够对形状进行采样。最简单的方法是使用形状的纹理。我不知道你是从哪里想到这涉及到后处理的:把这看作是一个额外的想法