2
0

shader从入门到放弃(3) 绘制函数

2026-09-09
2026-09-09

shader从入门到放弃(3) 绘制函数

绘制一个一次函数

点到直线的距离

d = \frac{Ax+By+C}{\sqrt{A^2+B^2}}
但是我们这个需要开平方,这个对程序很不友好,因此我们换个方法
换成向量的方法

点到直线的距离,向量法

image-Aeun.png
\vec{AD} = \frac{\vec{AC} \cdot\vec{AB}}{\vec{AB}\cdot\vec{AB}}\cdot \vec{AB}$

采用上面的公式,我会可以很方便计算相关的值。,因此给出代码

代码

最初版本,没有segement采样

float lineFunction(float x,float a, float b){
    return a * x + b;
}
//绘制坐标轴
vec3 drawAxis(vec2 uv){
    vec3 color = vec3(1.0);
    color = step(abs(uv.x),fwidth(uv.x)) * vec3(1,0,0) + step(abs(uv.y),fwidth(uv.y)) * vec3(0,1,0);
    return color;
}

// 点到直线距离
float getDot2LineDisatance(vec2 targetPoint,vec2 lineA, vec2 lineB){
    vec2 ab = lineB - lineA;
    vec2 ac = targetPoint - lineA;
    // 套公式
    vec2 ad = (dot(ac,ab) / dot(ab,ab)) * ab;
    return length(ac - ad);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 color = vec3(1.0);
    vec2 uv = (fragCoord.xy/ iResolution.xy - 0.5)*2.0;
    color = drawAxis(uv);
    
    //绘制直线
    float y = lineFunction(uv.x,1.0,0.);
    color = mix(color,vec3(0.0,0.0,1.0),step(getDot2LineDisatance(uv,vec2(0.,0.),vec2(1.0)),0.01));
    
    fragColor = vec4(color,1.0);
    
}
float lineFunction(float x,float a, float b){
    return a * x + b;
}
//绘制坐标轴
vec3 drawAxis(vec2 uv){
    vec3 color = vec3(1.0);
    color = step(abs(uv.x),fwidth(uv.x)) * vec3(1,0,0) + step(abs(uv.y),fwidth(uv.y)) * vec3(0,1,0);
    return color;
}

// 点到直线距离
float getDot2LineDisatance(vec2 targetPoint,vec2 lineA, vec2 lineB){
    vec2 ab = lineB - lineA;
    vec2 ac = targetPoint - lineA;
    // 套公式
    vec2 ad = (dot(ac,ab) / dot(ab,ab)) * ab;
    return length(ac - ad);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 color = vec3(1.0);
    vec2 uv = (fragCoord.xy/ iResolution.xy - 0.5)*2.0;
    color = drawAxis(uv);
    
    //绘制直线
    float y = lineFunction(uv.x,1.0,0.);
    color = mix(color,vec3(0.0,0.0,1.0),smoothstep(0.02,0.01,getDot2LineDisatance(uv,vec2(0.,0.),vec2(1.0))));
    
    fragColor = vec4(color,1.0);
    
}

上面是绘制光滑直线

加入了Segement采样划分区间

const int SIZE = 100;

float func(float x){
    return sin(x);
}
vec2 fixUV(vec2 uv){
   return 3.0 *(uv.xy/ iResolution.xy - 0.5)*2.0;
}
//绘制坐标轴
vec3 drawAxis(vec2 uv){
    vec3 color = vec3(1.0);
    color = step(abs(uv.x),fwidth(uv.x)) * vec3(1,0,0) + step(abs(uv.y),fwidth(uv.y)) * vec3(0,1,0);
    return color;
}

// 点到直线距离
float getDot2LineDisatance(vec2 targetPoint,vec2 lineA, vec2 lineB){
    vec2 ab = lineB - lineA;
    vec2 ac = targetPoint - lineA;
    // 套公式
    vec2 ad = clamp((dot(ac,ab) / dot(ab,ab)),0.0,1.0) * ab;
    return length(ac - ad);
}

//划分区间
//整个定义域,划分一次,只要是UV都会划分
//例如
float plotFunc(vec2 uv){
    float minDistance = 10000.0;
    for (int i = 0; i < SIZE; i++){
        // 当前 uv 的 X 可见范围为 -1 到 1。
        float t0 = float(i) / float(SIZE);
        float t1 = float(i+1) / float(SIZE);
        
        float fx = fixUV(vec2(mix(0.0,iResolution.x,t0),0.0)).x;
        float nfx = fixUV(vec2(mix(0.0,iResolution.x,t1),0.0)).x;
        
        vec2 pa = vec2(fx,func(fx));
        vec2 pb = vec2(nfx,func(nfx));
        
        float distanceToSegment = getDot2LineDisatance(uv, pa, pb);
        minDistance = min(minDistance, distanceToSegment);
    }
    
    return minDistance;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 color = vec3(1.0);
    vec2 uv = fixUV(fragCoord);
    color = drawAxis(uv);
    
    //绘制直线
    //float y = lineFunction(uv.x,1.0,0.);
    //color = mix(color,vec3(0.0,0.0,1.0),smoothstep(0.01,0.03,plotFunc(uv)));
    float curveMask = 1.0 - smoothstep(0.01, 0.03, plotFunc(uv));
    color = mix(color, vec3(0.0, 0.0, 1.0), curveMask);
    //color = vec3(smoothstep(0.3,0.01,plotFunc(uv)));
    fragColor = vec4(color,1.0);
    
}

上面这个是,这个是绘制三角形,效果还行,迭代100次。这个是暴力算法

这个是自己理解后改进的

const int SIZE = 100;

float func(float x){
    return sin(x);
}
vec2 fixUV(vec2 uv){
   return 3.0 *(uv.xy/ iResolution.xy - 0.5)*2.0;
}
//绘制坐标轴
vec3 drawAxis(vec2 uv){
    vec3 color = vec3(1.0);
    color = step(abs(uv.x),fwidth(uv.x)) * vec3(1,0,0) + step(abs(uv.y),fwidth(uv.y)) * vec3(0,1,0);
    return color;
}

// 点到直线距离
float getDot2LineDisatance(vec2 targetPoint,vec2 lineA, vec2 lineB){
    vec2 ab = lineB - lineA;
    vec2 ac = targetPoint - lineA;
    // 套公式
    vec2 ad = clamp((dot(ac,ab) / dot(ab,ab)),0.0,1.0) * ab;
    return length(ac - ad);
}

//划分区间
//整个定义域,划分一次,只要是UV都会划分
//例如
float plotFunc(vec2 uv){
    float minDistance = 10000.0;
    for (int i = 0; i < SIZE; i++){
        // 当前 uv 的 X 可见范围为 -1 到 1。
        float t0 = float(i) / float(SIZE);
        float t1 = float(i + 1) / float(SIZE);
        
        float fx = uv.x + t0;
        float nfx = uv.x + t1;
        
        vec2 pa = vec2(fx,func(fx));
        vec2 pb = vec2(nfx,func(nfx));
        
        float distanceToSegment = getDot2LineDisatance(uv, pa, pb);
        minDistance = min(minDistance, distanceToSegment);
    }
    
    return minDistance;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 color = vec3(1.0);
    vec2 uv = fixUV(fragCoord);
    color = drawAxis(uv);
    
    //绘制直线
    //float y = lineFunction(uv.x,1.0,0.);
    //color = mix(color,vec3(0.0,0.0,1.0),smoothstep(0.01,0.03,plotFunc(uv)));
    float curveMask = smoothstep(0.1, 0.003, plotFunc(uv));
    
    color = mix(color, vec3(0.0, 0.0, 1.0), curveMask);
    //color = vec3(smoothstep(0.3,0.01,plotFunc(uv)));
    //float y = func(uv.x);
    //float distance = getDot2LineDisatance()
    
    fragColor = vec4(color,1.0);
    
}

针对函数这种单值的,可以不需要细分,直接计算就行了

我的优化版本

const int SIZE = 100;

float func(float x){
    return sin(x) * sin(2.0*sin(3.0*x + 30.0));
}
vec2 fixUV(vec2 uv){
   return 3.0 *(uv.xy/ iResolution.xy - 0.5)*2.0;
}
//绘制坐标轴
vec3 drawAxis(vec2 uv){
    vec3 color = vec3(1.0);
    color = step(abs(uv.x),fwidth(uv.x)) * vec3(1,0,0) + step(abs(uv.y),fwidth(uv.y)) * vec3(0,1,0);
    return color;
}

// 点到直线距离
float getDot2LineDisatance(vec2 targetPoint,vec2 lineA, vec2 lineB){
    vec2 ab = lineB - lineA;
    vec2 ac = targetPoint - lineA;
    // 套公式
    vec2 ad = clamp((dot(ac,ab) / dot(ab,ab)),0.0,1.0) * ab;
    return length(ac - ad);
}



// 返回曲线遮罩:1 为曲线,0 为背景。
float plotFunc(vec2 uv)
{
    float field = uv.y - func(uv.x);
    return 1.0 - smoothstep(0.0, fwidth(field) * 1.5, abs(field));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 color = vec3(1.0);
    vec2 uv = fixUV(fragCoord);
    color = drawAxis(uv);
    
    //绘制直线
    //float y = lineFunction(uv.x,1.0,0.);
    //color = mix(color,vec3(0.0,0.0,1.0),smoothstep(0.01,0.03,plotFunc(uv)));
    
    //float curveMask = smoothstep(0.1, 0.003, plotFunc(uv));
    //color = mix(color, vec3(0.0, 0.0, 1.0), curveMask);
    
    float curveMask = plotFunc(uv);
    color = mix(color, vec3(0.0, 0.0, 1.0), curveMask);
    
    //color = vec3(smoothstep(0.3,0.01,plotFunc(uv)));
    //float y = func(uv.x);
    //float distance = getDot2LineDisatance()
    
    fragColor = vec4(color,1.0);
    
}

最简单的方法

评论