如何有效地在着色器中绘制直线和圆

时间:2019-05-22 20:43:53

标签: graphics glsl webgl shader

我已经使用此网站创建了一个着色器,用于显示一个雪人和一些雪花:
http://glslsandbox.com/e#54840.8
如果链接不起作用,请使用以下代码:

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
uniform sampler2D backbuffer;

#define PI 3.14159265

vec2 p;
float bt;


float seed=0.1;
float rand(){
    seed+=fract(sin(seed)*seed*1000.0)+.123;

    return mod(seed,1.0);
}


//No I don't know why he loks so creepy

float thicc=.003;
vec3 color=vec3(1.);
vec3 border=vec3(.4);



void diff(float p){
    if( (p)<thicc)
        gl_FragColor.rgb=color;
}
void line(vec2 a, vec2 b){

    vec2 q=p-a;

    vec2 r=normalize(b-a);

    if(dot(r,q)<0.){
        diff(length(q));
        return;
    }

    if(dot(r,q)>length(b-a)){
        diff(length(p-b));
        return;
    }

    vec2 rr=vec2(r.y,-r.x);




    diff(abs(dot(rr,q)));


}
void circle(vec2 m,float r){
    vec2 q=p-m;
    vec3 c=color;
    diff(length(q)-r);
    color=border;
    diff(abs(length(q)-r));
    color=c;
}

void main() {
    p=gl_FragCoord.xy/resolution.y;

    bt=mod(time,4.*PI);
    gl_FragColor.rgb=vec3(0.);

    vec2 last;


    //Body
    circle(vec2(1.,.250),.230); 
    circle(vec2(1.,.520),.180);
    circle(vec2(1.,.75),.13);

    //Nose
    color=vec3(1.,.4,.0);
    line(vec2(1,.720),vec2(1.020,.740));        
    line(vec2(1,.720),vec2(.980,.740));     
    line(vec2(1,.720),vec2(.980,.740));     
    line(vec2(1.020,.740),vec2(.980,.740));     


    border=vec3(0);
    color=vec3(1);
    thicc=.006;
    //Eyes

    circle(vec2(.930,.800),.014);
    circle(vec2(1.060,.800),.014);

    color=vec3(.0);
    thicc=0.;

    //mouth
    for(float x=0.;x<.1300;x+=.010)
        circle(vec2(.930+x,.680+cos(x*40.0+.5)*.014),.005); 


    //buttons
    for(float x=0.02;x<.450;x+=.070)
        circle(vec2(1.000,.150+x),0.01);    


    color=vec3(0.9);
    thicc=0.;

    //snowflakes
    for(int i=0;i<99;i++){
         circle(vec2(rand()*2.0,mod(rand()-time,1.0)),0.01);
    }

    gl_FragColor.a=1.0;



}

它的工作方式是,对于屏幕上的每个像素,着色器检查区域内的每个元素(按钮,身体,头部,眼睛,嘴巴,胡萝卜,雪花),然后替换当前元素。使用当前绘制颜色在该位置上绘制颜色。

因此,我们的复杂度为O(pixels_width * pixels_height * elements),导致当自己的屏幕上有太多的雪花时,着色器速度变慢。 所以现在我想知道如何优化此代码?我已经考虑过使用边界框甚至3d Octree(我想那是四叉树)来快速丢弃某个像素(或片段)区域之外的元素。

有人有另一个想法如何优化此着色器代码吗?请记住,每个着色器执行完全独立于所有其他着色器,并且我不能使用任何总体结构。

1 个答案:

答案 0 :(得分:0)

您需要将屏幕分成多个区域,“平铺”并计算每个图块的雪花。磁贴将具有相同数量的雪花并共享相同的种子,因此离开磁贴边界的一个粒子将具有相同的粒子进入下一个磁贴,从而使其看起来无缝。根据您的设置,图案可能仍会出现,但是您可以考虑根据最终的屏幕位置添加额外的统一变换。

顺便说一句,您可以通过删除所有条件分支(并在过程中看起来是抗锯齿的)来更有效地绘制圆形,并且可以摆脱length()生成的平方根。