Project

General

Profile

Download (27 KB) Statistics
| Branch: | Revision:

library / src / main / res / raw / main_vertex_shader.glsl @ a8537f43

1 d333eb6b Leszek Koltunski
//////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2016 Leszek Koltunski                                                          //
3
//                                                                                          //
4
// This file is part of Distorted.                                                          //
5
//                                                                                          //
6
// Distorted is free software: you can redistribute it and/or modify                        //
7
// it under the terms of the GNU General Public License as published by                     //
8
// the Free Software Foundation, either version 2 of the License, or                        //
9
// (at your option) any later version.                                                      //
10
//                                                                                          //
11
// Distorted is distributed in the hope that it will be useful,                             //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                           //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                            //
14
// GNU General Public License for more details.                                             //
15
//                                                                                          //
16
// You should have received a copy of the GNU General Public License                        // 
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                       //
18
//////////////////////////////////////////////////////////////////////////////////////////////
19
20 2e7ad49f Leszek Koltunski
precision lowp float;
21
22 f6cac1f6 Leszek Koltunski
uniform vec3 u_objD;                 // half of object width x half of object height X half the depth;
23
                                     // point (0,0,0) is the center of the object
24 6a06a912 Leszek Koltunski
25 f6cac1f6 Leszek Koltunski
uniform float u_Depth;               // max absolute value of v.z ; beyond that the vertex would be culled by the near or far planes.
26
                                     // I read OpenGL ES has a built-in uniform variable gl_DepthRange.near = n,
27
                                     // .far = f, .diff = f-n so maybe u_Depth is redundant
28
                                     // Update: this struct is only available in fragment shaders
29 6a06a912 Leszek Koltunski
                                
30 bfe2c61b Leszek Koltunski
uniform mat4 u_MVPMatrix;            // the combined model/view/projection matrix.
31
uniform mat4 u_MVMatrix;             // the combined model/view matrix.
32 6a06a912 Leszek Koltunski
		 
33 bfe2c61b Leszek Koltunski
attribute vec3 a_Position;           // Per-vertex position.
34
attribute vec3 a_Normal;             // Per-vertex normal vector.
35
attribute vec2 a_TexCoordinate;      // Per-vertex texture coordinate.
36 6a06a912 Leszek Koltunski
		  
37 f6cac1f6 Leszek Koltunski
varying vec3 v_Position;             //
38
varying vec3 v_Normal;               //
39
varying vec2 v_TexCoordinate;        //
40 6a06a912 Leszek Koltunski
41 f6cac1f6 Leszek Koltunski
uniform int vNumEffects;             // total number of vertex effects
42 6a06a912 Leszek Koltunski
43
#if NUM_VERTEX>0
44 f6cac1f6 Leszek Koltunski
uniform int vType[NUM_VERTEX];       // their types.
45
uniform vec4 vUniforms[3*NUM_VERTEX];// i-th effect is 3 consecutive vec4's: [3*i], [3*i+1], [3*i+2].
46
                                     // The first vec4 is the Interpolated values,
47
                                     // next is half cache half Center, the third -  the Region.
48 6a06a912 Leszek Koltunski
#endif
49
50
#if NUM_VERTEX>0
51 341c803d Leszek Koltunski
52
//////////////////////////////////////////////////////////////////////////////////////////////
53
// HELPER FUNCTIONS
54
//////////////////////////////////////////////////////////////////////////////////////////////
55 9420f2fe Leszek Koltunski
// The trick below is the if-less version of the
56 341c803d Leszek Koltunski
//
57
// t = dx<0.0 ? (u_objD.x-v.x) / (u_objD.x-ux) : (u_objD.x+v.x) / (u_objD.x+ux);
58
// h = dy<0.0 ? (u_objD.y-v.y) / (u_objD.y-uy) : (u_objD.y+v.y) / (u_objD.y+uy);
59
// d = min(t,h);
60
//
61
// float d = min(-ps.x/(sign(ps.x)*u_objD.x+p.x),-ps.y/(sign(ps.y)*u_objD.y+p.y))+1.0;
62
//
63
// We still have to avoid division by 0 when p.x = +- u_objD.x or p.y = +- u_objD.y (i.e on the edge of the Object)
64
// We do that by first multiplying the above 'float d' with sign(denominator1*denominator2)^2.
65
//
66
//////////////////////////////////////////////////////////////////////////////////////////////
67
// return degree of the point as defined by the bitmap rectangle
68
69
float degree_bitmap(in vec2 S, in vec2 PS)
70
  {
71
  vec2 A = sign(PS)*u_objD.xy + S;
72
73 369ee56a Leszek Koltunski
  vec2 signA = sign(A);                           //
74
  vec2 signA_SQ = signA*signA;                    // div = PS/A if A!=0, 0 otherwise.
75 20af7b69 Leszek Koltunski
  vec2 div = signA_SQ*PS/(A-(vec2(1,1)-signA_SQ));//
76 369ee56a Leszek Koltunski
77
  return 1.0-max(div.x,div.y);
78 341c803d Leszek Koltunski
  }
79
80
//////////////////////////////////////////////////////////////////////////////////////////////
81 9420f2fe Leszek Koltunski
// Return degree of the point as defined by the Region. Currently only supports circular regions.
82
//
83 73af5285 Leszek Koltunski
// Let us first introduce some notation.
84 9420f2fe Leszek Koltunski
// Let 'PS' be the vector from point P (the current vertex) to point S (the center of the effect).
85
// Let region.xy be the vector from point S to point O (the center point of the region circle)
86
// Let region.z be the radius of the region circle.
87 73af5285 Leszek Koltunski
// (This all should work regardless if S is inside or outside of the circle).
88
//
89
// Then, the degree of a point with respect to a given (circular!) Region is defined by:
90 9420f2fe Leszek Koltunski
//
91
// If P is outside the circle, return 0.
92 73af5285 Leszek Koltunski
// Otherwise, let X be the point where the halfline SP meets the region circle - then return |PX|/||SX|,
93 9420f2fe Leszek Koltunski
// aka the 'degree' of point P.
94
//
95 ff8ad0a7 Leszek Koltunski
// We solve the triangle OPX.
96 9420f2fe Leszek Koltunski
// We know the lengths |PO|, |OX| and the angle OPX, because cos(OPX) = cos(180-OPS) = -cos(OPS) = -PS*PO/(|PS|*|PO|)
97
// then from the law of cosines PX^2 + PO^2 - 2*PX*PO*cos(OPX) = OX^2 so PX = -a + sqrt(a^2 + OX^2 - PO^2)
98
// where a = PS*PO/|PS| but we are really looking for d = |PX|/(|PX|+|PS|) = 1/(1+ (|PS|/|PX|) ) and
99
// |PX|/|PS| = -b + sqrt(b^2 + (OX^2-PO^2)/PS^2) where b=PS*PO/|PS|^2 which can be computed with only one sqrt.
100 341c803d Leszek Koltunski
101 4fde55a0 Leszek Koltunski
float degree_region(in vec4 region, in vec2 PS)
102 341c803d Leszek Koltunski
  {
103
  vec2 PO  = PS + region.xy;
104
  float D = region.z*region.z-dot(PO,PO);      // D = |OX|^2 - |PO|^2
105 9420f2fe Leszek Koltunski
106
  if( D<=0.0 ) return 0.0;
107
108 341c803d Leszek Koltunski
  float ps_sq = dot(PS,PS);
109 20af7b69 Leszek Koltunski
  float one_over_ps_sq = 1.0/(ps_sq-(sign(ps_sq)-1.0));  // return 1.0 if ps_sq = 0.0
110
                                                         // Important: if we want to write
111
                                                         // b = 1/a if a!=0, b=1 otherwise
112
                                                         // we need to write that as
113
                                                         // b = 1 / ( a-(sign(a)-1) )
114
                                                         // [ and NOT 1 / ( a + 1 - sign(a) ) ]
115
                                                         // because the latter, if 0<a<2^-24,
116
                                                         // will suffer from round-off error and in this case
117
                                                         // a + 1.0 = 1.0 !! so 1 / (a+1-sign(a)) = 1/0 !
118 7c227ed2 Leszek Koltunski
  float DOT  = dot(PS,PO)*one_over_ps_sq;
119 341c803d Leszek Koltunski
120 9420f2fe Leszek Koltunski
  return 1.0 / (1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT));
121 341c803d Leszek Koltunski
  }
122
123
//////////////////////////////////////////////////////////////////////////////////////////////
124
// return min(degree_bitmap,degree_region). Just like degree_region, currently only supports circles.
125
126 4fde55a0 Leszek Koltunski
float degree(in vec4 region, in vec2 S, in vec2 PS)
127 341c803d Leszek Koltunski
  {
128
  vec2 PO  = PS + region.xy;
129
  float D = region.z*region.z-dot(PO,PO);      // D = |OX|^2 - |PO|^2
130 9420f2fe Leszek Koltunski
131
  if( D<=0.0 ) return 0.0;
132
133 341c803d Leszek Koltunski
  vec2 A = sign(PS)*u_objD.xy + S;
134 369ee56a Leszek Koltunski
  vec2 signA = sign(A);
135
  vec2 signA_SQ = signA*signA;
136 20af7b69 Leszek Koltunski
  vec2 div = signA_SQ*PS/(A-(vec2(1,1)-signA_SQ));
137 369ee56a Leszek Koltunski
  float E = 1.0-max(div.x,div.y);
138
139 341c803d Leszek Koltunski
  float ps_sq = dot(PS,PS);
140 20af7b69 Leszek Koltunski
  float one_over_ps_sq = 1.0/(ps_sq-(sign(ps_sq)-1.0));  // return 1.0 if ps_sq = 0.0
141 7c227ed2 Leszek Koltunski
  float DOT  = dot(PS,PO)*one_over_ps_sq;
142 341c803d Leszek Koltunski
143 9420f2fe Leszek Koltunski
  return min(1.0/(1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT)),E);
144 341c803d Leszek Koltunski
  }
145
146
//////////////////////////////////////////////////////////////////////////////////////////////
147
// Clamp v.z to (-u_Depth,u_Depth) with the following function:
148
// define h to be, say, 0.7; let H=u_Depth
149
//      if v.z < -hH then v.z = (-(1-h)^2 * H^2)/(v.z+(2h-1)H) -H   (function satisfying f(-hH)=-hH, f'(-hH)=1, lim f(x) = -H)
150
// else if v.z >  hH then v.z = (-(1-h)^2 * H^2)/(v.z-(2h-1)H) +H   (function satisfying f(+hH)=+hH, f'(+hH)=1, lim f(x) = +H)
151
// else v.z = v.z
152
153 291705f6 Leszek Koltunski
void restrictZ(inout float v)
154 341c803d Leszek Koltunski
  {
155
  const float h = 0.7;
156
  float signV = 2.0*max(0.0,sign(v))-1.0;
157
  float c = ((1.0-h)*(h-1.0)*u_Depth*u_Depth)/(v-signV*(2.0*h-1.0)*u_Depth) +signV*u_Depth;
158
  float b = max(0.0,sign(abs(v)-h*u_Depth));
159
160
  v = b*c+(1.0-b)*v; // Avoid branching: if abs(v)>h*u_Depth, then v=c; otherwise v=v.
161
  }
162
163 6a06a912 Leszek Koltunski
//////////////////////////////////////////////////////////////////////////////////////////////
164 341c803d Leszek Koltunski
// DEFORM EFFECT
165
//
166 18d15f2f Leszek Koltunski
// Deform the whole shape of the Object by force V. Algorithm is as follows:
167
//
168
// Suppose we apply force (Vx,Vy) at point (Cx,Cy) (i.e. the center of the effect). Then, first of all,
169
// divide the rectangle into 4 smaller rectangles along the 1 horizontal + 1 vertical lines that pass
170
// through (Cx,Cy). Now suppose we have already understood the following case:
171
//
172
// A vertical (0,Vy) force applied to a rectangle (WxH) in size, at center which is the top-left corner
173
// of the rectangle.  (*)
174
//
175
// If we understand (*), then we understand everything, because in order to compute the movement of the
176
// whole rectangle we can apply (*) 8 times: for each one of the 4 sub-rectangles, apply (*) twice,
177
// once for the vertical component of the force vector, the second time for the horizontal one.
178
//
179
// Let's then compute (*):
180
// 1) the top-left point will move by exactly (0,Vy)
181
// 2) we arbitrarily decide that the top-right point will move by (|Vy|/(|Vy|+A*W))*Vy, where A is some
182
//    arbitrary constant (const float A below). The F(V,W) = (|Vy|/(|Vy|+A*W)) comes from the following:
183
//    a) we want F(V,0) = 1
184
//    b) we want lim V->inf (F) = 1
185
//    c) we actually want F() to only depend on W/V, which we have here.
186
// 3) then the top edge of the rectangle will move along the line Vy*G(x), where G(x) = (1 - (A*W/(|Vy|+A*W))*(x/W)^2)
187
// 4) Now we decide that the left edge of the rectangle will move along Vy*H(y), where H(y) = (1 - |y|/(|Vy|+C*|y|))
188
//    where C is again an arbitrary constant. Again, H(y) comes from the requirement that no matter how
189
//    strong we push the left edge of the rectangle up or down, it can never 'go over itself', but its
190
//    length will approach 0 if squeezed very hard.
191
// 5) The last point we need to compute is the left-right motion of the top-right corner (i.e. if we push
192
//    the top-left corner up very hard, we want to have the top-right corner not only move up, but also to
193
//    the left at least a little bit).
194
//    We arbitrarily decide that, in addition to moving up-down by Vy*F(V,W), the corner will also move
195
//    left-right by I(V,W) = B*W*F(V,W), where B is again an arbitrary constant.
196
// 6) combining 3), 4) and 5) together, we arrive at a movement of an arbitrary point (x,y) away from the
197
//    top-left corner:
198
//    X(x,y) = -B*x * (|Vy|/(|Vy|+A*W)) * (1-(y/H)^2)                               (**)
199
//    Y(x,y) = Vy * (1 - |y|/(|Vy|+C*|y|)) * (1 - (A*W/(|Vy|+A*W))*(x/W)^2)         (**)
200
//
201
// We notice that formulas (**) have been construed so that it is possible to continously mirror them
202
// left-right and up-down (i.e. apply not only to the 'bottom-right' rectangle of the 4 subrectangles
203
// but to all 4 of them!).
204
//
205
// Constants:
206
// a) A : valid values: (0,infinity). 'Bendiness' if the surface - the higher A is, the more the surface
207 6ebdbbf1 Leszek Koltunski
//        bends. A<=0 destroys the system.
208 18d15f2f Leszek Koltunski
// b) B : valid values: <-1,1>. The amount side edges get 'sucked' inwards when we pull the middle of the
209
//        top edge up. B=0 --> not at all, B=1: a looot. B=-0.5: the edges will actually be pushed outwards
210
//        quite a bit. One can also set it to <-1 or >1, but it will look a bit ridiculous.
211
// c) C : valid values: <1,infinity). The derivative of the H(y) function at 0, i.e. the rate of 'squeeze'
212
//        surface gets along the force line. C=1: our point gets pulled very closely to points above it
213
//        even when we apply only small vertical force to it. The higher C is, the more 'uniform' movement
214
//        along the force line is.
215
//        0<=C<1 looks completely ridiculous and C<0 destroys the system.
216
217 a8537f43 Leszek Koltunski
void deform(in int effect, inout vec3 v, inout vec3 n)
218 6a06a912 Leszek Koltunski
  {
219 6ebdbbf1 Leszek Koltunski
  const vec2 ONE = vec2(1.0,1.0);
220 18d15f2f Leszek Koltunski
221 dbeddd9d Leszek Koltunski
  const float A = 0.5;
222 18d15f2f Leszek Koltunski
  const float B = 0.2;
223
  const float C = 5.0;
224 dbeddd9d Leszek Koltunski
225 fa6c352d Leszek Koltunski
  vec2 center = vUniforms[effect+1].yz;
226 6ebdbbf1 Leszek Koltunski
  vec2 ps     = center-v.xy;
227
  vec2 aPS    = abs(ps);
228
  vec2 maxps  = u_objD.xy + abs(center);
229 b86265d6 Leszek Koltunski
  float d     = degree_region(vUniforms[effect+2],ps);
230
  vec3 force  = vUniforms[effect].xyz * d;
231
  vec2 aForce = abs(force.xy);
232
  float denom = dot(ps+(1.0-d)*force.xy,ps);
233
  float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0));
234 6ebdbbf1 Leszek Koltunski
  vec2 Aw = A*maxps;
235
  vec2 quot = ps / maxps;
236 18d15f2f Leszek Koltunski
  quot = quot*quot;                          // ( (x/W)^2 , (y/H)^2 ) where x,y are distances from V to center
237
238
  float denomV = 1.0 / (aForce.y + Aw.x);
239
  float denomH = 1.0 / (aForce.x + Aw.y);
240 dbeddd9d Leszek Koltunski
241 44efc8a8 Leszek Koltunski
  vec2 vertCorr= ONE - aPS / ( aForce+C*aPS + (ONE-sign(aForce)) );  // avoid division by 0 when force and PS both are 0
242 dbeddd9d Leszek Koltunski
243 6ebdbbf1 Leszek Koltunski
  float mvXvert = -B * ps.x * aForce.y * (1.0-quot.y) * denomV;      // impact the vertical   component of the force vector has on horizontal movement
244
  float mvYhorz = -B * ps.y * aForce.x * (1.0-quot.x) * denomH;      // impact the horizontal component of the force vector has on vertical   movement
245 18d15f2f Leszek Koltunski
  float mvYvert =  force.y * (1.0-quot.x*Aw.x*denomV) * vertCorr.y;  // impact the vertical   component of the force vector has on vertical   movement
246
  float mvXhorz = -force.x * (1.0-quot.y*Aw.y*denomH) * vertCorr.x;  // impact the horizontal component of the force vector has on horizontal movement
247 dbeddd9d Leszek Koltunski
248
  v.x -= (mvXvert+mvXhorz);
249
  v.y -= (mvYvert+mvYhorz);
250 b86265d6 Leszek Koltunski
251
  v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0);                          // thick bubble
252
  float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom;//
253
254
  n.xy += n.z*b*ps;
255 6a06a912 Leszek Koltunski
  }
256
257
//////////////////////////////////////////////////////////////////////////////////////////////
258 341c803d Leszek Koltunski
// DISTORT EFFECT
259 6a06a912 Leszek Koltunski
//
260
// Point (Px,Py) gets moved by vector (Wx,Wy,Wz) where Wx/Wy = Vx/Vy i.e. Wx=aVx and Wy=aVy where 
261
// a=Py/Sy (N --> when (Px,Py) is above (Sx,Sy)) or a=Px/Sx (W) or a=(w-Px)/(w-Sx) (E) or a=(h-Py)/(h-Sy) (S) 
262
// It remains to be computed which of the N,W,E or S case we have: answer: a = min[ Px/Sx , Py/Sy , (w-Px)/(w-Sx) , (h-Py)/(h-Sy) ]
263
// Computations above are valid for screen (0,0)x(w,h) but here we have (-w/2,-h/2)x(w/2,h/2)
264
//  
265
// the vertical part
266
// Let |(v.x,v.y),(ux,uy)| = |PS|, ux-v.x=dx,uy-v.y=dy, f(x) (0<=x<=|SX|) be the shape of the side of the bubble.
267
// H(v.x,v.y) = |PS|>|SX| ? 0 : f(|PX|)
268
// N(v.x,v.y) = |PS|>|SX| ? (0,0,1) : ( -(dx/|PS|)sin(beta), -(dy/|PS|)sin(beta), cos(beta) ) where tan(beta) is f'(|PX|) 
269
// ( i.e. normalize( dx, dy, -|PS|/f'(|PX|))         
270
//
271
// Now we also have to take into account the effect horizontal move by V=(u_dVx[i],u_dVy[i]) will have on the normal vector.
272
// Solution: 
273
// 1. Decompose the V into two subcomponents, one parallel to SX and another perpendicular.
274
// 2. Convince yourself (draw!) that the perpendicular component has no effect on normals.
275 30925500 Leszek Koltunski
// 3. The parallel component changes the length of |SX| by the factor of a=(|SX|-|Vpar|)/|SX| (where the length
276
//    can be negative depending on the direction)
277 6a06a912 Leszek Koltunski
// 4. that in turn leaves the x and y parts of the normal unchanged and multiplies the z component by a!
278
//
279
// |Vpar| = (u_dVx[i]*dx - u_dVy[i]*dy) / sqrt(ps_sq) = (Vx*dx-Vy*dy)/ sqrt(ps_sq)  (-Vy because y is inverted)
280
// a =  (|SX| - |Vpar|)/|SX| = 1 - |Vpar|/((sqrt(ps_sq)/(1-d)) = 1 - (1-d)*|Vpar|/sqrt(ps_sq) = 1-(1-d)*(Vx*dx-Vy*dy)/ps_sq 
281
//
282
// Side of the bubble
283
// 
284
// choose from one of the three bubble shapes: the cone, the thin bubble and the thick bubble          
285
// Case 1: 
286
// f(t) = t, i.e. f(x) = uz * x/|SX|   (a cone)
287
// -|PS|/f'(|PX|) = -|PS|*|SX|/uz but since ps_sq=|PS|^2 and d=|PX|/|SX| then |PS|*|SX| = ps_sq/(1-d)
288
// so finally -|PS|/f'(|PX|) = -ps_sq/(uz*(1-d))
289
//                    
290
// Case 2: 
291
// f(t) = 3t^2 - 2t^3 --> f(0)=0, f'(0)=0, f'(1)=0, f(1)=1 (the bell curve)
292
// here we have t = x/|SX| which makes f'(|PX|) = 6*uz*|PS|*|PX|/|SX|^3.
293
// so -|PS|/f'(|PX|) = (-|SX|^3)/(6uz|PX|) =  (-|SX|^2) / (6*uz*d) but
294
// d = |PX|/|SX| and ps_sq = |PS|^2 so |SX|^2 = ps_sq/(1-d)^2
295
// so finally -|PS|/f'(|PX|) = -ps_sq/ (6uz*d*(1-d)^2)
296
//                  
297
// Case 3:
298 73af5285 Leszek Koltunski
// 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,
299 30925500 Leszek Koltunski
// f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!
300 6a06a912 Leszek Koltunski
// then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12uz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!) 
301
// so finally -|PS|/f'(|PX|) = -ps_sq/ (12uz*d*(1-d)^3)  
302
//
303
// Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.
304 73af5285 Leszek Koltunski
// 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 ).
305 6a06a912 Leszek Koltunski
// 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) 
306 73af5285 Leszek Koltunski
// 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
307
// can simply add up the first and second components.
308 6a06a912 Leszek Koltunski
//
309 30925500 Leszek Koltunski
// Thus we actually want to compute N(v.x,v.y) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding
310
// the first two components. (a is the horizontal part)
311 6a06a912 Leszek Koltunski
        
312 a8537f43 Leszek Koltunski
void distort(in int effect, inout vec3 v, inout vec3 n)
313 6a06a912 Leszek Koltunski
  {
314 fa6c352d Leszek Koltunski
  vec2 center = vUniforms[effect+1].yz;
315 4fde55a0 Leszek Koltunski
  vec2 ps = center-v.xy;
316 a7067deb Leszek Koltunski
  vec3 force = vUniforms[effect].xyz;
317 4fde55a0 Leszek Koltunski
  float d = degree(vUniforms[effect+2],center,ps);
318 a7067deb Leszek Koltunski
  float denom = dot(ps+(1.0-d)*force.xy,ps);
319
  float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0));          // = denom==0 ? 1000:1/denom;
320 30925500 Leszek Koltunski
321 a7067deb Leszek Koltunski
  //v.z += force.z*d;                                                  // cone
322
  //b = -(force.z*(1.0-d))*one_over_denom;                             //
323 6a06a912 Leszek Koltunski
        
324 a7067deb Leszek Koltunski
  //v.z += force.z*d*d*(3.0-2.0*d);                                    // thin bubble
325
  //b = -(6.0*force.z*d*(1.0-d)*(1.0-d))*one_over_denom;               //
326 6a06a912 Leszek Koltunski
        
327 a7067deb Leszek Koltunski
  v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0);                            // thick bubble
328
  float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom;  //
329 6a06a912 Leszek Koltunski
                
330 a7067deb Leszek Koltunski
  v.xy += d*force.xy;
331
  n.xy += n.z*b*ps;
332 6a06a912 Leszek Koltunski
  }
333
 
334
//////////////////////////////////////////////////////////////////////////////////////////////
335 341c803d Leszek Koltunski
// SINK EFFECT
336
//
337 82ee855a Leszek Koltunski
// Pull P=(v.x,v.y) towards center of the effect with P' = P + (1-h)*dist(S-P)
338
// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(S-P)
339 6a06a912 Leszek Koltunski
 
340 a8537f43 Leszek Koltunski
void sink(in int effect,inout vec3 v)
341 6a06a912 Leszek Koltunski
  {
342 fa6c352d Leszek Koltunski
  vec2 center = vUniforms[effect+1].yz;
343 4fde55a0 Leszek Koltunski
  vec2 ps = center-v.xy;
344 6a06a912 Leszek Koltunski
  float h = vUniforms[effect].x;
345 4fde55a0 Leszek Koltunski
  float t = degree(vUniforms[effect+2],center,ps) * (1.0-h)/max(1.0,h);
346 6a06a912 Leszek Koltunski
  
347
  v.xy += t*ps;           
348
  }
349
350 82ee855a Leszek Koltunski
//////////////////////////////////////////////////////////////////////////////////////////////
351
// PINCH EFFECT
352
//
353
// Pull P=(v.x,v.y) towards the line that
354
// a) passes through the center of the effect
355
// b) forms angle defined in the 2nd interpolated value with the X-axis
356
// with P' = P + (1-h)*dist(line to P)
357
// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(line to P)
358
359 a8537f43 Leszek Koltunski
void pinch(in int effect,inout vec3 v)
360 82ee855a Leszek Koltunski
  {
361
  vec2 center = vUniforms[effect+1].yz;
362
  vec2 ps = center-v.xy;
363
  float h = vUniforms[effect].x;
364
  float t = degree(vUniforms[effect+2],center,ps) * (1.0-h)/max(1.0,h);
365
  float angle = vUniforms[effect].y;
366
  vec2 dir = vec2(sin(angle),-cos(angle));
367
368
  v.xy += t*dot(ps,dir)*dir;
369
  }
370
371 6a06a912 Leszek Koltunski
//////////////////////////////////////////////////////////////////////////////////////////////
372 341c803d Leszek Koltunski
// SWIRL EFFECT
373 6a06a912 Leszek Koltunski
//
374
// Let d be the degree of the current vertex V with respect to center of the effect S and Region vRegion.
375
// This effect rotates the current vertex V by vInterpolated.x radians clockwise around the circle dilated 
376
// by (1-d) around the center of the effect S.
377
378 a8537f43 Leszek Koltunski
void swirl(in int effect, inout vec3 v)
379 6a06a912 Leszek Koltunski
  {
380 fa6c352d Leszek Koltunski
  vec2 center  = vUniforms[effect+1].yz;
381 4fde55a0 Leszek Koltunski
  vec2 PS = center-v.xy;
382
  vec4 SO = vUniforms[effect+2];
383 6a06a912 Leszek Koltunski
  float d1_circle = degree_region(SO,PS);
384 4fde55a0 Leszek Koltunski
  float d1_bitmap = degree_bitmap(center,PS);
385 5b1c0f47 Leszek Koltunski
386
  float alpha = vUniforms[effect].x;
387
  float sinA = sin(alpha);
388
  float cosA = cos(alpha);
389
390 4fde55a0 Leszek Koltunski
  vec2 PS2 = vec2( PS.x*cosA+PS.y*sinA,-PS.x*sinA+PS.y*cosA ); // vector PS rotated by A radians clockwise around center.
391
  vec4 SG = (1.0-d1_circle)*SO;                                // coordinates of the dilated circle P is going to get rotated around
392
  float d2 = max(0.0,degree(SG,center,PS2));                   // make it a max(0,deg) because otherwise when center=left edge of the
393 20af7b69 Leszek Koltunski
                                                               // bitmap some points end up with d2<0 and they disappear off view.
394 4fde55a0 Leszek Koltunski
  v.xy += min(d1_circle,d1_bitmap)*(PS - PS2/(1.0-d2));        // if d2=1 (i.e P=center) we should have P unchanged. How to do it?
395
  }
396
397
//////////////////////////////////////////////////////////////////////////////////////////////
398
// WAVE EFFECT
399
//
400
// Directional sinusoidal wave effect.
401 73af5285 Leszek Koltunski
//
402
// This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) )  (*)
403
// i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
404
// point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
405
//
406
// In this case V is defined by angles A and B (sines and cosines of which are precomputed in
407
// EffectQueueVertex and passed in the uniforms).
408
// 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
409
// to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
410
//
411
// Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
412
//
413 57297c51 Leszek Koltunski
//////////////////////////////////////////////////////////////////////////////////////////////
414 73af5285 Leszek Koltunski
// How to compute any generic effect of type (*)
415 57297c51 Leszek Koltunski
//////////////////////////////////////////////////////////////////////////////////////////////
416 73af5285 Leszek Koltunski
//
417
// By definition, the vertices move by f(x,y)*V.
418
//
419
// Normals are much more complicated.
420 57297c51 Leszek Koltunski
// Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
421
// Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
422 73af5285 Leszek Koltunski
//
423
// Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
424
// has 2 tangent vectors given by
425
//
426 c6ea3680 Leszek Koltunski
// SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx);  (**)
427
// SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy);  (***)
428 73af5285 Leszek Koltunski
//
429
// and then obviously the normal N is given by N= SX x SY .
430
//
431
// We still need to remember the note from the distort function about adding up normals:
432
// we first need to 'normalize' the normals to make their third components equal, and then we
433
// simply add up the first and the second component while leaving the third unchanged.
434
//
435
// How to see facts (**) and (***) ? Briefly:
436
// a) compute the 2D analogon and conclude that in this case the tangent SX is given by
437
//    SX = ( cosA*f'(x) +1, sinA*f'(x) )    (where A is the angle vector V makes with X axis )
438
// b) cut the resulting surface with plane P which
439
//    - includes vector V
440
//    - crosses plane XY along line parallel to X axis
441
// c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
442
//    and our surface (I am talking about the tangent vector which belongs to P) is given by
443 c6ea3680 Leszek Koltunski
//    (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
444
//
445
//    Matrix of rotation:
446
//
447
//    |sinY|  cosY
448
//    -cosY  |sinY|
449
//
450 73af5285 Leszek Koltunski
// d) compute the above and see that this is equal precisely to SX from (**).
451
// e) repeat points b,c,d in direction Y and come up with (***).
452 f256e1a5 Leszek Koltunski
//
453 5b1c0f47 Leszek Koltunski
//////////////////////////////////////////////////////////////////////////////////////////////
454 f256e1a5 Leszek Koltunski
// Note: we should avoid passing certain combinations of parameters to this function. One such known
455
// combination is ( A: small but positive, B: any, amplitude >= length ).
456
// In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
457
// amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
458
// very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
459
// points very dark)
460
//
461
// Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
462 4fde55a0 Leszek Koltunski
463 a8537f43 Leszek Koltunski
void wave(in int effect, inout vec3 v, inout vec3 n)
464 4fde55a0 Leszek Koltunski
  {
465 fa6c352d Leszek Koltunski
  vec2 center     = vUniforms[effect+1].yz;
466 02ef26bc Leszek Koltunski
  float amplitude = vUniforms[effect  ].x;
467 d0c902b8 Leszek Koltunski
  float length    = vUniforms[effect  ].y;
468 02ef26bc Leszek Koltunski
469 06d71892 Leszek Koltunski
  vec2 ps = center - v.xy;
470 9ea4f88f Leszek Koltunski
  float deg = amplitude*degree_region(vUniforms[effect+2],ps);
471 815869cb Leszek Koltunski
472 39b80df0 Leszek Koltunski
  if( deg != 0.0 && length != 0.0 )
473 9ea4f88f Leszek Koltunski
    {
474 ea16dc89 Leszek Koltunski
    float phase = vUniforms[effect  ].z;
475 350cc2f5 Leszek Koltunski
    float alpha = vUniforms[effect  ].w;
476
    float beta  = vUniforms[effect+1].x;
477 5b1c0f47 Leszek Koltunski
478
    float sinA = sin(alpha);
479
    float cosA = cos(alpha);
480
    float sinB = sin(beta);
481
    float cosB = cos(beta);
482 39b80df0 Leszek Koltunski
483 ea16dc89 Leszek Koltunski
    float angle= 1.578*(ps.x*cosB-ps.y*sinB) / length + phase;
484 57297c51 Leszek Koltunski
485 350cc2f5 Leszek Koltunski
    vec3 dir= vec3(sinB*cosA,cosB*cosA,sinA);
486 39b80df0 Leszek Koltunski
487 a8537f43 Leszek Koltunski
    v += sin(angle)*deg*dir;
488 39b80df0 Leszek Koltunski
489 73af5285 Leszek Koltunski
    if( n.z != 0.0 )
490
      {
491
      float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z);
492
      float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z);
493 39b80df0 Leszek Koltunski
494 73af5285 Leszek Koltunski
      float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY);
495
      float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY);
496
      float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX);
497
      float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX);
498 39b80df0 Leszek Koltunski
499 57297c51 Leszek Koltunski
      float abs_z = dir.z <0.0 ? -(sinX*sinY) : (sinX*sinY);
500 c6ea3680 Leszek Koltunski
501 73af5285 Leszek Koltunski
      float tmp = 1.578*cos(angle)*deg/length;
502 39b80df0 Leszek Koltunski
503 57297c51 Leszek Koltunski
      float fx =-cosB*tmp;
504 73af5285 Leszek Koltunski
      float fy = sinB*tmp;
505 39b80df0 Leszek Koltunski
506 57297c51 Leszek Koltunski
      vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,abs_z*fx);
507
      vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,abs_z*fy);
508 39b80df0 Leszek Koltunski
509 73af5285 Leszek Koltunski
      vec3 normal = cross(sx,sy);
510 39b80df0 Leszek Koltunski
511 fe3cee39 Leszek Koltunski
      if( normal.z<=0.0 )                   // Why this bizarre shit rather than the straightforward
512
        {                                   //
513
        normal.x= 0.0;                      // if( normal.z>0.0 )
514
        normal.y= 0.0;                      //   {
515
        normal.z= 1.0;                      //   n.x = (n.x*normal.z + n.z*normal.x);
516
        }                                   //   n.y = (n.y*normal.z + n.z*normal.y);
517
                                            //   n.z = (n.z*normal.z);
518
                                            //   }
519
      n.x = (n.x*normal.z + n.z*normal.x);  //
520
      n.y = (n.y*normal.z + n.z*normal.y);  // ? Because if we do the above, my shitty Nexus4 crashes
521
      n.z = (n.z*normal.z);                 // during shader compilation!
522 39b80df0 Leszek Koltunski
      }
523 9ea4f88f Leszek Koltunski
    }
524 6a06a912 Leszek Koltunski
  }
525
526
#endif
527
528
//////////////////////////////////////////////////////////////////////////////////////////////
529
  		  
530
void main()                                                 	
531
  {              
532 a8537f43 Leszek Koltunski
  vec3 v = 2.0*u_objD*a_Position;
533
  vec3 n = a_Normal;
534 6a06a912 Leszek Koltunski
535
#if NUM_VERTEX>0
536
  for(int i=0; i<vNumEffects; i++)
537
    {
538
         if( vType[i]==DISTORT) distort(3*i,v,n);
539 b86265d6 Leszek Koltunski
    else if( vType[i]==DEFORM ) deform (3*i,v,n);
540 341c803d Leszek Koltunski
    else if( vType[i]==SINK   ) sink   (3*i,v);
541 82ee855a Leszek Koltunski
    else if( vType[i]==PINCH  ) pinch  (3*i,v);
542 341c803d Leszek Koltunski
    else if( vType[i]==SWIRL  ) swirl  (3*i,v);
543 9ea4f88f Leszek Koltunski
    else if( vType[i]==WAVE   ) wave   (3*i,v,n);
544 6a06a912 Leszek Koltunski
    }
545
 
546 291705f6 Leszek Koltunski
  restrictZ(v.z);
547 6a06a912 Leszek Koltunski
#endif
548
   
549 a8537f43 Leszek Koltunski
  v_Position      = v;
550 2dacdeb2 Leszek Koltunski
  v_TexCoordinate = a_TexCoordinate;
551 a8537f43 Leszek Koltunski
  v_Normal        = normalize(vec3(u_MVMatrix*vec4(n,0.0)));
552
  gl_Position     = u_MVPMatrix*vec4(v,1.0);
553 d333eb6b Leszek Koltunski
  }