Revision 73af5285
Added by Leszek Koltunski about 9 years ago
| src/main/res/raw/main_vertex_shader.glsl | ||
|---|---|---|
| 78 | 78 | 
    //////////////////////////////////////////////////////////////////////////////////////////////  | 
| 79 | 79 | 
    // Return degree of the point as defined by the Region. Currently only supports circular regions.  | 
| 80 | 80 | 
    //  | 
| 81 | 
    // Let us first introduce some notation.  | 
|
| 81 | 82 | 
    // Let 'PS' be the vector from point P (the current vertex) to point S (the center of the effect).  | 
| 82 | 
    // Should work regardless if S is inside or outside of the circle.  | 
|
| 83 | 83 | 
    // Let region.xy be the vector from point S to point O (the center point of the region circle)  | 
| 84 | 84 | 
    // Let region.z be the radius of the region circle.  | 
| 85 | 
    // (This all should work regardless if S is inside or outside of the circle).  | 
|
| 86 | 
    //  | 
|
| 87 | 
    // Then, the degree of a point with respect to a given (circular!) Region is defined by:  | 
|
| 85 | 88 | 
    //  | 
| 86 | 89 | 
    // If P is outside the circle, return 0.  | 
| 87 | 
    // Otherwise, let X be the point where the halfline SP meets the region circle - return |PX|/||SX|,  | 
|
| 90 | 
    // Otherwise, let X be the point where the halfline SP meets the region circle - then return |PX|/||SX|,
   | 
|
| 88 | 91 | 
    // aka the 'degree' of point P.  | 
| 89 | 92 | 
    //  | 
| 90 | 93 | 
    // We solve the triangle OPX.  | 
| ... | ... | |
| 267 | 270 | 
    // so finally -|PS|/f'(|PX|) = -ps_sq/ (6uz*d*(1-d)^2)  | 
| 268 | 271 | 
    //  | 
| 269 | 272 | 
    // Case 3:  | 
| 270 | 
    // f(t) = 3t^4-8t^3+6t^2 would be better as this safisfies f(0)=0, f'(0)=0, f'(1)=0, f(1)=1,
   | 
|
| 273 | 
    // f(t) = 3t^4-8t^3+6t^2 would be better as this satisfies f(0)=0, f'(0)=0, f'(1)=0, f(1)=1,
   | 
|
| 271 | 274 | 
    // f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!  | 
| 272 | 275 | 
    // then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12uz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!)  | 
| 273 | 276 | 
    // so finally -|PS|/f'(|PX|) = -ps_sq/ (12uz*d*(1-d)^3)  | 
| 274 | 277 | 
    //  | 
| 275 | 278 | 
    // Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.  | 
| 276 | 
    // If a surface is given by z = f(x,y), then the normal vector at (x0,y0) is given by (df/dx (x0,y0), df/dy (x0,y0), 1 ).
   | 
|
| 279 | 
    // If a surface is given by z = f(x,y), then the normal vector at (x0,y0) is given by (-df/dx (x0,y0), -df/dy (x0,y0), 1 ).
   | 
|
| 277 | 280 | 
    // so if we have two surfaces defined by f1(x,y) and f2(x,y) with their normals expressed as (f1x,f1y,1) and (f2x,f2y,1)  | 
| 278 | 
    // then the normal to g = f1+f2 is simply given by (f1x+f2x,f1y+f2y,1), i.e. if the third component is 1, then we can simply
   | 
|
| 279 | 
    // add up the first and second components.  | 
|
| 281 | 
    // then the normal to g = f1+f2 is simply given by (f1x+f2x,f1y+f2y,1), i.e. if the third components are equal, then we
   | 
|
| 282 | 
    // can simply add up the first and second components.
   | 
|
| 280 | 283 | 
    //  | 
| 281 | 284 | 
    // Thus we actually want to compute N(v.x,v.y) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding  | 
| 282 | 285 | 
    // the first two components. (a is the horizontal part)  | 
| ... | ... | |
| 346 | 349 | 
    // WAVE EFFECT  | 
| 347 | 350 | 
    //  | 
| 348 | 351 | 
    // Directional sinusoidal wave effect.  | 
| 352 | 
    //  | 
|
| 353 | 
    // This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) ) (*)  | 
|
| 354 | 
    // i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each  | 
|
| 355 | 
    // point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).  | 
|
| 356 | 
    //  | 
|
| 357 | 
    // In this case V is defined by angles A and B (sines and cosines of which are precomputed in  | 
|
| 358 | 
    // EffectQueueVertex and passed in the uniforms).  | 
|
| 359 | 
    // Let's move V to start at the origin O, let point C be the endpoint of V, and let C' be C's projection  | 
|
| 360 | 
    // to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).  | 
|
| 361 | 
    //  | 
|
| 362 | 
    // Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.  | 
|
| 363 | 
    //  | 
|
| 364 | 
    ////////////////////////////////////////////////////////  | 
|
| 365 | 
    // How to compute any generic effect of type (*)  | 
|
| 366 | 
    ////////////////////////////////////////////////////////  | 
|
| 367 | 
    //  | 
|
| 368 | 
    // By definition, the vertices move by f(x,y)*V.  | 
|
| 369 | 
    //  | 
|
| 370 | 
    // Normals are much more complicated.  | 
|
| 371 | 
    // Let angle X be the angle (0,Vy,Vz)((0,Vy,0)(Vx,Vy,Vz).  | 
|
| 372 | 
    // Let angle Y be the angle (Vx,0,Vz)((Vx,0,0)(Vx,Vy,Vz).  | 
|
| 373 | 
    //  | 
|
| 374 | 
    // Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,  | 
|
| 375 | 
    // has 2 tangent vectors given by  | 
|
| 376 | 
    //  | 
|
| 377 | 
    // SX = (1.0+cosX*fx , cosY*sinX*fx , sinY*sinX*fx); (**)  | 
|
| 378 | 
    // SY = (cosX*sinY*fy , 1.0+cosY*fy , sinX*sinY*fy); (***)  | 
|
| 379 | 
    //  | 
|
| 380 | 
    // and then obviously the normal N is given by N= SX x SY .  | 
|
| 381 | 
    //  | 
|
| 382 | 
    // We still need to remember the note from the distort function about adding up normals:  | 
|
| 383 | 
    // we first need to 'normalize' the normals to make their third components equal, and then we  | 
|
| 384 | 
    // simply add up the first and the second component while leaving the third unchanged.  | 
|
| 385 | 
    //  | 
|
| 386 | 
    // How to see facts (**) and (***) ? Briefly:  | 
|
| 387 | 
    // a) compute the 2D analogon and conclude that in this case the tangent SX is given by  | 
|
| 388 | 
    // SX = ( cosA*f'(x) +1, sinA*f'(x) ) (where A is the angle vector V makes with X axis )  | 
|
| 389 | 
    // b) cut the resulting surface with plane P which  | 
|
| 390 | 
    // - includes vector V  | 
|
| 391 | 
    // - crosses plane XY along line parallel to X axis  | 
|
| 392 | 
    // c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P  | 
|
| 393 | 
    // and our surface (I am talking about the tangent vector which belongs to P) is given by  | 
|
| 394 | 
    // (1+cosX*fx,0,sinX*fx) rotated by angle Y (where angles X,Y are defined above) along vector (1,0,0).  | 
|
| 395 | 
    // d) compute the above and see that this is equal precisely to SX from (**).  | 
|
| 396 | 
    // e) repeat points b,c,d in direction Y and come up with (***).  | 
|
| 349 | 397 | 
     | 
| 350 | 398 | 
    void wave(in int effect, inout vec4 v, inout vec4 n)  | 
| 351 | 399 | 
      {
   | 
| ... | ... | |
| 363 | 411 | 
    float sinB = vUniforms[effect ].w;  | 
| 364 | 412 | 
    float cosB = vUniforms[effect+1].y;  | 
| 365 | 413 | 
     | 
| 366 | 
        float angle= 1.578*(-ps.x*cosB-ps.y*sinB) / length;  // -ps.x and -ps.y becuase the 'ps=center-v.xy' inverts the XY axis!
   | 
|
| 414 | 
        float angle= 1.578*(-ps.x*cosB-ps.y*sinB) / length;  // -ps.x and -ps.y because the 'ps=center-v.xy' inverts the XY axis!
   | 
|
| 367 | 415 | 
    vec3 dir = vec3(sinB*cosA,cosB*cosA,sinA);  | 
| 368 | 416 | 
     | 
| 369 | 417 | 
    v.xyz += sin(angle)*deg*dir;  | 
| 370 | 418 | 
     | 
| 371 | 
    float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z);  | 
|
| 372 | 
    float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z);  | 
|
| 419 | 
    if( n.z != 0.0 )  | 
|
| 420 | 
          {
   | 
|
| 421 | 
    float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z);  | 
|
| 422 | 
    float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z);  | 
|
| 373 | 423 | 
     | 
| 374 | 
    float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY);  | 
|
| 375 | 
    float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY);  | 
|
| 376 | 
    float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX);  | 
|
| 377 | 
    float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX);  | 
|
| 424 | 
          float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY);
   | 
|
| 425 | 
          float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY);
   | 
|
| 426 | 
          float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX);
   | 
|
| 427 | 
          float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX);
   | 
|
| 378 | 428 | 
     | 
| 379 | 
    float tmp = 1.578*cos(angle)*deg/length;  | 
|
| 429 | 
          float tmp = 1.578*cos(angle)*deg/length;
   | 
|
| 380 | 430 | 
     | 
| 381 | 
    float fx = cosB*tmp;  | 
|
| 382 | 
    float fy = sinB*tmp;  | 
|
| 431 | 
          float fx = cosB*tmp;
   | 
|
| 432 | 
          float fy = sinB*tmp;
   | 
|
| 383 | 433 | 
     | 
| 384 | 
    vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,sinY*sinX*fx);  | 
|
| 385 | 
    vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,sinX*sinY*fy);  | 
|
| 434 | 
          vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,sinY*sinX*fx);
   | 
|
| 435 | 
          vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,sinX*sinY*fy);
   | 
|
| 386 | 436 | 
     | 
| 387 | 
    vec3 normal = cross(sx,sy);  | 
|
| 437 | 
          vec3 normal = cross(sx,sy);
   | 
|
| 388 | 438 | 
     | 
| 389 | 
    if( n.z != 0.0 )  | 
|
| 390 | 
          {
   | 
|
| 391 | 
    n.xyz = n.z*normal;  | 
|
| 439 | 
    if( normal.z > 0.0 )  | 
|
| 440 | 
            {
   | 
|
| 441 | 
    n.xy += (n.z/normal.z)*vec2(normal.x,normal.y);  | 
|
| 442 | 
    }  | 
|
| 392 | 443 | 
    }  | 
| 393 | 444 | 
    }  | 
| 394 | 445 | 
    }  | 
Also available in: Unified diff
Now we can add up the WAVE effect to others with smooth shading! Remaining issues:
- when angle A < 0, the shades are wrong
- sometimes (check with the 3D vertex & Fragment effects' app) we get black spots at seemingly random points. Looks like computational instability again.