如何在Shader中绘制类似虚线的折线

如何在Shader中绘制类似虚线的折线

实例代码可以参考shadertoy中的[例子](line with animation (shadertoy.com))

核心思想

绘制折线

在shader中无法通过顺序绘制的方式绘制折线,在参考现有的shadertoy中的例子后,决定采用距离场的方式绘制折线,即计算屏幕上每个像素到给定折线的距离,通过给定线宽来选取折线的范围。

绘制虚线

通过距离场明确线的范围后,可以将屏幕中每个像素投影到折线上,通过投影到折线上的距离来对线段进行分段,以实现间隔绘制效果。

效果图如下:

如何在Shader中绘制类似虚线的折线

详细代码

sdLine_t方法用于绘制线段,方法中通过向量点乘的方式计算,给定点到线段的最短距离,其中c为计算得到的p距离向量ab的最短距离。t_lxsp在向量ab上的投影的距离。通过对c进行截取,仅保留给定线宽的计算结果,线宽范围外的赋值为0,即可得到折线的绘制范围。

通过对t_lxs取模,可以实现分段绘制,距离加时间可以实现流动效果。

最后cDistance_t方法实现多段线段的绘制,方法中使用max来混和多段线。

const float ELIPSE=.005;
const float LINEWIDTH=0.01;

float sdLine_t(in vec2 p,in vec2 a, in vec2 b){
    vec2 pa=p-a,ba=b-a;
    float t=dot(pa,ba)/dot(ba,ba);
    //p在ba上投影距离
    float t_lxs=dot(pa,ba)/length(ba);

    float c=length(pa-ba*clamp(t,0.0,1.0));
    c=1.-smoothstep(LINEWIDTH,LINEWIDTH+ELIPSE,c);

    return c*mod(t_lxs-iTime/10.,.1);
}

const vec2 p0 = vec2( 0.6, 0.1);
const vec2 p1 = vec2( 0.4, 0.3);
const vec2 p2 = vec2(-0.2, 0.5);
const vec2 p3 = vec2(-0.6, 0.4);
const vec2 p4 = vec2(-0.8, 0.1);
const vec2 p5 = vec2(-0.7,-0.1);
const vec2 p6 = vec2( 0.0,-0.2);
const vec2 p7 = vec2( 0.7,-0.2);

float cDistance_t( in vec2 v )
{
    float d0 = sdLine_t( v, p0, p1 );
    float d1 = sdLine_t( v, p1, p2 );
    float d2 = sdLine_t( v, p2, p3 );
    float d3 = sdLine_t( v, p3, p4 );
    float d4 = sdLine_t( v, p4, p5 );
    float d5 = sdLine_t( v, p5, p6 );
    float d6 = sdLine_t( v, p6, p7 );
    float d7 = sdLine_t( v, p7, p0 );
	//线宽范围外均为0,所以这里取最大值
    float t=max(d0,max(d1,max(d2,max(d3,max(d4,max(d5,d6))))));
    return t*8.;
}

void mainImage(out vec4 fragColor,in vec2 fragCoord){
    float m=min(iResolution.x,iResolution.y);
    vec2 p=(-iResolution.xy+2.*fragCoord.xy)/m;

    float c_lxs=cDistance_t(p);
    fragColor=vec4(vec3(c_lxs),1.0);
}
上一篇:Shadertoy_入门基础


下一篇:折纸效果! Cocos Creator 3.0