0

这是我当前的 C 代码,它可以做我想做的事情,但它依赖glBlendEquation(GL_MAX)于 WebGL 中不可用的代码。我想要的是渲染一条摇摆不定的模糊线。我可以使用高斯模糊,但它必须有一个非常大的半径(16 像素),我希望它会非常慢。

请注意,为了清楚起见,我删除了一些 gl 状态管理代码和其他一些东西,但代码应该按原样工作。

现有的 C 代码:

static const char *pnt_vtx_shader =
    "#version 110\n"
    "varying vec2 uv;\n"
    "void main() {\n"
    "    uv = (gl_MultiTexCoord0.st - 1.0f);\n"
    "    gl_Position = gl_Vertex;\n"
    "}";

static const char *pnt_shader_src =
    "#version 110\n"
    "varying vec2 uv;\n"
    "void main() {\n"
    "    gl_FragColor = vec4(exp(-4.5f*0.5f*log2(dot(uv,uv)+1.0f)));\n"
    "}";


GLuint shader_prog ;
int samp;
float pw, ph;

float sco_verts[128*8*4];
int sco_ind[128*3*6];


void init(int width, int height, int num_samp)
{

    pw = 0.5f*fmaxf(1.0f/24, 8.0f/width), ph = 0.5f*fmaxf(1.0f/24, 8.0f/height);
    samp = num_samp;

    // helper function, compiles and links the shader, prints out any errors
    shader_prog = compile_program(pnt_vtx_shader, pnt_shader_src);

    for(int i=0; i<samp; i++) {
        sco_verts[(i*8+0)*4+0] = 0; sco_verts[(i*8+0)*4+1] = 2;
        sco_verts[(i*8+1)*4+0] = 0; sco_verts[(i*8+1)*4+1] = 0;
        sco_verts[(i*8+2)*4+0] = 1; sco_verts[(i*8+2)*4+1] = 2;
        sco_verts[(i*8+3)*4+0] = 1; sco_verts[(i*8+3)*4+1] = 0;
        sco_verts[(i*8+4)*4+0] = 1; sco_verts[(i*8+4)*4+1] = 2;
        sco_verts[(i*8+5)*4+0] = 1; sco_verts[(i*8+5)*4+1] = 0;
        sco_verts[(i*8+6)*4+0] = 2; sco_verts[(i*8+6)*4+1] = 2;
        sco_verts[(i*8+7)*4+0] = 2; sco_verts[(i*8+7)*4+1] = 0;
    }

    for(int i=0; i<samp; i++) {
        sco_ind[(i*6+0)*3+0] = i*8+0; sco_ind[(i*6+0)*3+1] = i*8+1; sco_ind[(i*6+0)*3+2] = i*8+3;
        sco_ind[(i*6+1)*3+0] = i*8+0; sco_ind[(i*6+1)*3+1] = i*8+3; sco_ind[(i*6+1)*3+2] = i*8+2;

        sco_ind[(i*6+2)*3+0] = i*8+2; sco_ind[(i*6+2)*3+1] = i*8+4; sco_ind[(i*6+2)*3+2] = i*8+5;
        sco_ind[(i*6+3)*3+0] = i*8+2; sco_ind[(i*6+3)*3+1] = i*8+5; sco_ind[(i*6+3)*3+2] = i*8+3;

        sco_ind[(i*6+4)*3+0] = i*8+4; sco_ind[(i*6+4)*3+1] = i*8+6; sco_ind[(i*6+4)*3+2] = i*8+7;
        sco_ind[(i*6+5)*3+0] = i*8+4; sco_ind[(i*6+5)*3+1] = i*8+7; sco_ind[(i*6+5)*3+2] = i*8+5;
    }
}

// getsamp does some averaging over samples
static float getsamp(const float *data, int len, int i, int w) {
    float sum = 0, err = 0;
    int l = IMAX(i-w, 0);
    int u = IMIN(i+w, len);
    for(int i = l; i < u; i++)
        sum+= data[i];
    return sum / (2*w);
}

// R holds a rotation matrix... it's the transpose of what you would give GL though
// because of reasons :P (I wrote code that did all the stuff from this program in
// software first and the GL version shares a bunch of code with that one)
// data is audio samples, [-1, 1], the length of the array is in len
void render_scope(float R[3][3], const float *data, int len)
{
    // do the rotate/project ourselves because the GL matrix won't do the right
    // thing if we just send it our verticies, we want wour tris to always be 
    // parrallel to the view plane, because we're actually drawing a fuzzy line
    // not a 3D object
    // also it makes it easier to match the software implementation
    float px, py;
    {
        float s = getsamp(data, len, 0, len/96);
        s=copysignf(log2f(fabsf(s)*3+1)/2, s);
        float xt = -0.5f, yt = 0.2f*s, zt = 0.0f;
        float x = R[0][0]*xt + R[1][0]*yt + R[2][0]*zt;
        float y = R[0][1]*xt + R[1][1]*yt + R[2][1]*zt;
        float z = R[0][2]*xt + R[1][2]*yt + R[2][2]*zt;
        const float zvd = 1/(z+2);
        px=x*zvd*4/3; py=y*zvd*4/3;
    }

    for(int i=0; i<samp; i++) {
        float s = getsamp(data, len, (i+1)*len/(samp), len/96);
        s=copysignf(log2f(fabsf(s)*3+1)/2, s);

        float xt = (i+1 - (samp)/2.0f)*(1.0f/(samp)), yt = 0.2f*s, zt = 0.0f;
        float x = R[0][0]*xt + R[1][0]*yt + R[2][0]*zt;
        float y = R[0][1]*xt + R[1][1]*yt + R[2][1]*zt;
        float z = R[0][2]*xt + R[1][2]*yt + R[2][2]*zt;
        const float zvd = 1/(z+2);
        x=x*zvd*4/3; y=y*zvd*4/3;

        const float dx=x-px, dy=y-py;
        const float d = 1/hypotf(dx, dy);
        const float tx=dx*d*pw, ty=dy*d*pw;
        const float nx=-dy*d*pw, ny=dx*d*ph;

        sco_verts[(i*8+0)*4+2] = px-nx-tx; sco_verts[(i*8+0)*4+3] = py-ny-ty;
        sco_verts[(i*8+1)*4+2] = px+nx-tx; sco_verts[(i*8+1)*4+3] = py+ny-ty;
        sco_verts[(i*8+2)*4+2] = px-nx   ; sco_verts[(i*8+2)*4+3] = py-ny;
        sco_verts[(i*8+3)*4+2] = px+nx   ; sco_verts[(i*8+3)*4+3] = py+ny;
        sco_verts[(i*8+4)*4+2] =  x-nx   ; sco_verts[(i*8+4)*4+3] =  y-ny;
        sco_verts[(i*8+5)*4+2] =  x+nx   ; sco_verts[(i*8+5)*4+3] =  y+ny;
        sco_verts[(i*8+6)*4+2] =  x-nx+tx; sco_verts[(i*8+6)*4+3] =  y-ny+ty;
        sco_verts[(i*8+7)*4+2] =  x+nx+tx; sco_verts[(i*8+7)*4+3] =  y+ny+ty;
        px=x,py=y;
    }

    glEnable(GL_BLEND);
    glBlendEquation(GL_MAX);
    glUseProgram(shader_prog);

    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glTexCoordPointer(2, GL_FLOAT, sizeof(float)*4, sco_verts);
    glVertexPointer(2, GL_FLOAT, sizeof(float)*4, sco_verts + 2);
    glDrawElements(GL_TRIANGLES, samp*3*6, GL_UNSIGNED_INT, sco_ind);
}

这是一个测试应用程序的屏幕截图,我不确定这个屏幕截图中的线宽是否正确......但它给出了这个想法,而且我会使用更多的点,这样线条会更平滑。

截屏

4

0 回答 0