使用 2D metaballs 绘制具有恒定厚度的轮廓
Using 2D metaballs to draw an outline with a constant thickness
我将 metaballs 的概念应用到我正在制作的游戏中,以显示玩家已经选择了几艘船,就像这样 http://prntscr.com/klgktf
但是,我的目标是保持此轮廓的粗细不变,这不是我使用当前代码得到的结果。
我正在使用 GLSL 着色器来执行此操作,并将一个统一的船舶位置数组传递给碎片着色器 (u_metaballs)。
顶点着色器:
#version 120
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
碎片着色器:
#version 120
uniform vec2 u_metaballs[128];
void main() {
float intensity = 0;
for(int i = 0; i < 128 && u_metaballs[i].x != 0; i++){
float r = length(u_metaballs[i] - gl_FragCoord.xy);
intensity += 1 / r;
}
gl_FragColor = vec4(0, 0, 0, 0);
if(intensity > .2 && intensity < .21)
gl_FragColor = vec4(.5, 1, .7, .2);
}
我试过调整强度范围,甚至将 1 / r 更改为 10000 / (r ^ 4) 这(虽然没有任何意义)有点帮助,但它不能解决问题。
如有任何帮助或建议,我们将不胜感激。
经过更多的教导,即使在单次通过中也是可行的......你只需计算到最近的元球的距离,如果小于或等于边界厚度渲染片段,否则丢弃它......这里的例子(假设单四边形<-1,+1>
渲染覆盖整个屏幕):
顶点:
// Vertex
varying vec2 pos; // fragment position in world space
void main()
{
pos=gl_Vertex.xy;
gl_Position=ftransform();
}
片段:
// Fragment
#version 120
varying vec2 pos;
const float r=0.3; // metabal radius
const float w=0.02; // border line thickness
uniform vec2 u_metaballs[5]=
{
vec2(-0.25,-0.25),
vec2(+0.25,-0.25),
vec2( 0.00,+0.05),
vec2(+0.30,+0.35),
vec2(-1000.1,-1000.1), // end of metaballs
};
void main()
{
int i;
float d;
// d = min distance to any metaball
for (d=r+r+w+w,i=0;u_metaballs[i].x>-1000.0;i++)
d=min(d,length(pos-u_metaballs[i].xy));
// if outside range ignore fragment
if ((d<r)||(d>r+w)) discard;
// otherwise render it
gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}
预览:
我将 metaballs 的概念应用到我正在制作的游戏中,以显示玩家已经选择了几艘船,就像这样 http://prntscr.com/klgktf
但是,我的目标是保持此轮廓的粗细不变,这不是我使用当前代码得到的结果。
我正在使用 GLSL 着色器来执行此操作,并将一个统一的船舶位置数组传递给碎片着色器 (u_metaballs)。
顶点着色器:
#version 120
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
碎片着色器:
#version 120
uniform vec2 u_metaballs[128];
void main() {
float intensity = 0;
for(int i = 0; i < 128 && u_metaballs[i].x != 0; i++){
float r = length(u_metaballs[i] - gl_FragCoord.xy);
intensity += 1 / r;
}
gl_FragColor = vec4(0, 0, 0, 0);
if(intensity > .2 && intensity < .21)
gl_FragColor = vec4(.5, 1, .7, .2);
}
我试过调整强度范围,甚至将 1 / r 更改为 10000 / (r ^ 4) 这(虽然没有任何意义)有点帮助,但它不能解决问题。
如有任何帮助或建议,我们将不胜感激。
经过更多的教导,即使在单次通过中也是可行的......你只需计算到最近的元球的距离,如果小于或等于边界厚度渲染片段,否则丢弃它......这里的例子(假设单四边形<-1,+1>
渲染覆盖整个屏幕):
顶点:
// Vertex
varying vec2 pos; // fragment position in world space
void main()
{
pos=gl_Vertex.xy;
gl_Position=ftransform();
}
片段:
// Fragment
#version 120
varying vec2 pos;
const float r=0.3; // metabal radius
const float w=0.02; // border line thickness
uniform vec2 u_metaballs[5]=
{
vec2(-0.25,-0.25),
vec2(+0.25,-0.25),
vec2( 0.00,+0.05),
vec2(+0.30,+0.35),
vec2(-1000.1,-1000.1), // end of metaballs
};
void main()
{
int i;
float d;
// d = min distance to any metaball
for (d=r+r+w+w,i=0;u_metaballs[i].x>-1000.0;i++)
d=min(d,length(pos-u_metaballs[i].xy));
// if outside range ignore fragment
if ((d<r)||(d>r+w)) discard;
// otherwise render it
gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}
预览: