Revision 18d15f2f
Added by Leszek Koltunski about 8 years ago
src/main/res/raw/main_vertex_shader.glsl | ||
---|---|---|
161 | 161 |
////////////////////////////////////////////////////////////////////////////////////////////// |
162 | 162 |
// DEFORM EFFECT |
163 | 163 |
// |
164 |
// Deform the whole shape of the Object by force V |
|
165 |
// |
|
166 |
// If the point of application (Sx,Sy) is on the upper edge of the Object, then: |
|
167 |
// a) ignore Vz |
|
168 |
// b) change shape of the whole Object in the following way: |
|
169 |
// Suppose the upper-left corner of the Object rectangle is point L, upper-right - R, force vector V |
|
170 |
// is applied to point M on the upper edge, width of the Object = w, height = h, |LM| = Wl, |MR| = Wr, |
|
171 |
// force vector V=(Vx,Vy). Also let H = h/(h+Vy) |
|
172 |
// |
|
173 |
// Let now L' and R' be points such that vec(LL') = Wr/w * vec(V) and vec(RR') = Wl/w * vec(V) |
|
174 |
// now let Vl be a point on the line segment L --> M+vec(V) such that Vl(y) = L'(y) |
|
175 |
// and let Vr be a point on the line segment R --> M+vec(V) such that Vr(y) = R'(y) |
|
176 |
// |
|
177 |
// Now define points Fl and Fr, the points L and R will be moved to under force V, with Fl(y)=L'(y) |
|
178 |
// and Fr(y)=R'(y) and |VrFr|/|VrR'| = |VlFl|/|VlL'| = H |
|
179 |
// Now notice that |VrR'| = |VlL'| = Wl*Wr / w ( a little geometric puzzle! ) |
|
180 |
// |
|
181 |
// Then points L,R under force V move by vectors vec(Fl), vec(Fr) where |
|
182 |
// vec(Fl) = (Wr/w) * [ (Vx+Wl)-Wl*H, Vy ] = (Wr/w) * [ Wl*Vy / (h+Vy) + Vx, Vy ] |
|
183 |
// vec(Fr) = (Wl/w) * [ (Vx-Wr)+Wr*H, Vy ] = (Wl/w) * [-Wr*Vy / (h+Vy) + Vx, Vy ] |
|
184 |
// |
|
185 |
// Lets now denote M+vec(V) = M'. The line segment LMR gets distorted to the curve Fl-M'-Fr. Let's |
|
186 |
// now arbitrarilly decide that: |
|
187 |
// a) at point Fl the curve has to be parallel to line LM' |
|
188 |
// b) at point M' - to line LR |
|
189 |
// c) at point Fr - to line M'R |
|
190 |
// |
|
191 |
// Now if Fl=(flx,fly) , M'=(mx,my) , Fr=(frx,fry); direction vector at Fl is (vx,vy) and at M' |
|
192 |
// is (+c,0) where +c is some positive constant, then the parametric equations of the Fl--->M' |
|
193 |
// section of the curve (which has to satisfy (X(0),Y(0)) = Fl, (X(1),Y(1))=M', |
|
194 |
// (X'(0),Y'(0)) = (vx,vy), (X'(1),Y'(1)) = (+c,0) ) is |
|
195 |
// |
|
196 |
// X(t) = ( (mx-flx)-vx )t^2 + vx*t + flx (*) |
|
197 |
// Y(t) = ( vy - 2(my-fly) )t^3 + ( 3(my-fly) -2vy )t^2 + vy*t + fly |
|
198 |
// |
|
199 |
// Here we have to have X'(1) = 2(mx-flx)-vx which is positive <==> vx<2(mx-flx). We also have to |
|
200 |
// have vy<2(my-fly) so that Y'(t)>0 (this is a must otherwise we have local loops!) |
|
201 |
// Similarly for the Fr--->M' part of the curve we have the same equation except for the fact that |
|
202 |
// this time we have to have X'(1)<0 so now we have to have vx>2(mx-frx). |
|
203 |
// |
|
204 |
// If we are stretching the left or right edge of the bitmap then the only difference is that we |
|
205 |
// have to have (X'(1),Y'(1)) = (0,+-c) with + or - c depending on which part of the curve |
|
206 |
// we are tracing. Then the parametric equation is |
|
207 |
// |
|
208 |
// X(t) = ( vx - 2(mx-flx) )t^3 + ( 3(mx-flx) -2vx )t^2 + vx*t + flx |
|
209 |
// Y(t) = ( (my-fly)-vy )t^2 + vy*t + fly |
|
210 |
// |
|
211 |
// If we are dragging the top edge: |
|
212 |
// |
|
213 |
// Then point (x,h/2) on the top edge will move by vector (X(t),Y(t)) where those functions are |
|
214 |
// given by (*) and t = x < dSx ? (w/2+x)/(w/2+dSx) : (w/2-x)/(w/2-dSx) (-w/2 < x < +w/2 !) |
|
215 |
// (this is 'vec2 time' below in the code). |
|
216 |
// Any point (x,y) will move by vector (a*X(t),a*Y(t)) where a is (y+h/2)/h |
|
217 |
|
|
164 |
// Deform the whole shape of the Object by force V. Algorithm is as follows: |
|
165 |
// |
|
166 |
// Suppose we apply force (Vx,Vy) at point (Cx,Cy) (i.e. the center of the effect). Then, first of all, |
|
167 |
// divide the rectangle into 4 smaller rectangles along the 1 horizontal + 1 vertical lines that pass |
|
168 |
// through (Cx,Cy). Now suppose we have already understood the following case: |
|
169 |
// |
|
170 |
// A vertical (0,Vy) force applied to a rectangle (WxH) in size, at center which is the top-left corner |
|
171 |
// of the rectangle. (*) |
|
172 |
// |
|
173 |
// If we understand (*), then we understand everything, because in order to compute the movement of the |
|
174 |
// whole rectangle we can apply (*) 8 times: for each one of the 4 sub-rectangles, apply (*) twice, |
|
175 |
// once for the vertical component of the force vector, the second time for the horizontal one. |
|
176 |
// |
|
177 |
// Let's then compute (*): |
|
178 |
// 1) the top-left point will move by exactly (0,Vy) |
|
179 |
// 2) we arbitrarily decide that the top-right point will move by (|Vy|/(|Vy|+A*W))*Vy, where A is some |
|
180 |
// arbitrary constant (const float A below). The F(V,W) = (|Vy|/(|Vy|+A*W)) comes from the following: |
|
181 |
// a) we want F(V,0) = 1 |
|
182 |
// b) we want lim V->inf (F) = 1 |
|
183 |
// c) we actually want F() to only depend on W/V, which we have here. |
|
184 |
// 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) |
|
185 |
// 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|)) |
|
186 |
// where C is again an arbitrary constant. Again, H(y) comes from the requirement that no matter how |
|
187 |
// strong we push the left edge of the rectangle up or down, it can never 'go over itself', but its |
|
188 |
// length will approach 0 if squeezed very hard. |
|
189 |
// 5) The last point we need to compute is the left-right motion of the top-right corner (i.e. if we push |
|
190 |
// the top-left corner up very hard, we want to have the top-right corner not only move up, but also to |
|
191 |
// the left at least a little bit). |
|
192 |
// We arbitrarily decide that, in addition to moving up-down by Vy*F(V,W), the corner will also move |
|
193 |
// left-right by I(V,W) = B*W*F(V,W), where B is again an arbitrary constant. |
|
194 |
// 6) combining 3), 4) and 5) together, we arrive at a movement of an arbitrary point (x,y) away from the |
|
195 |
// top-left corner: |
|
196 |
// X(x,y) = -B*x * (|Vy|/(|Vy|+A*W)) * (1-(y/H)^2) (**) |
|
197 |
// Y(x,y) = Vy * (1 - |y|/(|Vy|+C*|y|)) * (1 - (A*W/(|Vy|+A*W))*(x/W)^2) (**) |
|
198 |
// |
|
199 |
// We notice that formulas (**) have been construed so that it is possible to continously mirror them |
|
200 |
// left-right and up-down (i.e. apply not only to the 'bottom-right' rectangle of the 4 subrectangles |
|
201 |
// but to all 4 of them!). |
|
202 |
// |
|
203 |
// Constants: |
|
204 |
// a) A : valid values: (0,infinity). 'Bendiness' if the surface - the higher A is, the more the surface |
|
205 |
// bends. A<=0 destroys the system, |
|
206 |
// b) B : valid values: <-1,1>. The amount side edges get 'sucked' inwards when we pull the middle of the |
|
207 |
// top edge up. B=0 --> not at all, B=1: a looot. B=-0.5: the edges will actually be pushed outwards |
|
208 |
// quite a bit. One can also set it to <-1 or >1, but it will look a bit ridiculous. |
|
209 |
// c) C : valid values: <1,infinity). The derivative of the H(y) function at 0, i.e. the rate of 'squeeze' |
|
210 |
// surface gets along the force line. C=1: our point gets pulled very closely to points above it |
|
211 |
// even when we apply only small vertical force to it. The higher C is, the more 'uniform' movement |
|
212 |
// along the force line is. |
|
213 |
// 0<=C<1 looks completely ridiculous and C<0 destroys the system. |
|
214 |
|
|
218 | 215 |
void deform(in int effect, inout vec4 v) |
219 | 216 |
{ |
217 |
const vec2 one = vec2(1.0,1.0); |
|
218 |
|
|
220 | 219 |
const float A = 0.5; |
221 |
const float B = 0.3; |
|
220 |
const float B = 0.2; |
|
221 |
const float C = 5.0; |
|
222 | 222 |
|
223 | 223 |
vec2 center = vUniforms[effect+1].yz; |
224 | 224 |
vec2 force = vUniforms[effect].xy; |
... | ... | |
229 | 229 |
|
230 | 230 |
vec2 Aw = A*maxdist; |
231 | 231 |
vec2 quot = dist / maxdist; |
232 |
quot = quot*quot; // ( (x/W)^2 , (y/H)^2 ) where x,y are distances from V to center |
|
233 |
|
|
234 |
float denomV = 1.0 / (aForce.y + Aw.x); |
|
235 |
float denomH = 1.0 / (aForce.x + Aw.y); |
|
232 | 236 |
|
233 |
float mvXvert =-((B*dist.x*aForce.y)/(aForce.y + Aw.x))*(1.0-quot.y*quot.y); |
|
234 |
float mvYvert = force.y*( 1.0 - quot.x*quot.x*(Aw.x/(aForce.y+Aw.x)) ) * aForce.y/(aForce.y+aDist.y); |
|
237 |
vec2 vertCorr= one - aDist / ( aForce+C*aDist + (one-sign(aForce)) ); |
|
235 | 238 |
|
236 |
float mvXhorz =-force.x*( 1.0 - quot.y*quot.y*(Aw.y/(aForce.x+Aw.y)) ) * aForce.x/(aForce.x+aDist.x); |
|
237 |
float mvYhorz =-((B*dist.y*aForce.x)/(aForce.x + Aw.y))*(1.0-quot.x*quot.x); |
|
239 |
float mvXvert = -B * dist.x * aForce.y * (1.0-quot.y) * denomV; // impact the vertical component of the force vector has on horizontal movement |
|
240 |
float mvYhorz = -B * dist.y * aForce.x * (1.0-quot.x) * denomH; // impact the horizontal component of the force vector has on vertical movement |
|
241 |
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 |
|
242 |
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 |
|
238 | 243 |
|
239 | 244 |
v.x -= (mvXvert+mvXhorz); |
240 | 245 |
v.y -= (mvYvert+mvYhorz); |
Also available in: Unified diff
Polish up DEFORM.