Project

General

Profile

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

library / src / main / java / org / distorted / library / effect / VertexEffectDistort.java @ 0f10a0b6

1 125cee3d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2017 Leszek Koltunski                                                               //
3
//                                                                                               //
4 46b572b5 Leszek Koltunski
// This file is part of Distorted.                                                               //
5 125cee3d Leszek Koltunski
//                                                                                               //
6 46b572b5 Leszek Koltunski
// Distorted is free software: you can redistribute it and/or modify                             //
7 125cee3d Leszek Koltunski
// 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 46b572b5 Leszek Koltunski
// Distorted is distributed in the hope that it will be useful,                                  //
12 125cee3d Leszek Koltunski
// 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 46b572b5 Leszek Koltunski
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18 125cee3d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.library.effect;
21
22
import org.distorted.library.type.Data3D;
23
import org.distorted.library.type.Data4D;
24
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26 faa3ff56 Leszek Koltunski
/**
27
 * Distort the Mesh by applying a 3D vector of force.
28
 */
29 125cee3d Leszek Koltunski
public class VertexEffectDistort extends VertexEffect
30
  {
31 0dd98279 Leszek Koltunski
  private Data3D mVector, mCenter;
32
  private Data4D mRegion;
33
34 125cee3d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
35 6bb59aad Leszek Koltunski
/**
36 faa3ff56 Leszek Koltunski
 * Only for use by the library itself.
37 6bb59aad Leszek Koltunski
 *
38 faa3ff56 Leszek Koltunski
 * @y.exclude
39 6bb59aad Leszek Koltunski
 */
40 15aa7d94 Leszek Koltunski
  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
41
    {
42 b24e4719 Leszek Koltunski
    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
43
    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
44 7bebb196 Leszek Koltunski
    return mVector.get(uniforms,index,currentDuration,step);
45 125cee3d Leszek Koltunski
    }
46 7cd24173 leszek
47 faa3ff56 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
48
// PUBLIC API
49 7cd24173 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
50 353f7580 Leszek Koltunski
// Def: P-current vertex being distorted, S - center of the effect, X- point where half-line SP meets
51
// the region circle (if P is inside the circle); (Vx,Vy,Vz) - force vector.
52
//
53
// horizontal part
54
// Point (Px,Py) gets moved by vector (Wx,Wy) where Wx/Wy = Vx/Vy i.e. Wx=aVx and Wy=aVy where
55 7cd24173 leszek
// 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)
56
// 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) ]
57
// Computations above are valid for screen (0,0)x(w,h) but here we have (-w/2,-h/2)x(w/2,h/2)
58
//
59 353f7580 Leszek Koltunski
// vertical part
60
// Let vector PS = (dx,dy), f(x) (0<=x<=|SX|) be the shape of the side of the bubble.
61
// H(Px,Py) = |PS|>|SX| ? 0 : f(|PX|)
62
// N(Px,Py) = |PS|>|SX| ? (0,0,1) : ( -(dx/|PS|)sin(beta), -(dy/|PS|)sin(beta), cos(beta) ) where tan(beta) is f'(|PX|)
63
// ( i.e. normalize( dx, dy, -|PS|/f'(|PX|) )
64 7cd24173 leszek
//
65 353f7580 Leszek Koltunski
// Now we also have to take into account the effect horizontal move by V=(Vx,Vy) will have on the normal vector.
66 7cd24173 leszek
// Solution:
67
// 1. Decompose the V into two subcomponents, one parallel to SX and another perpendicular.
68
// 2. Convince yourself (draw!) that the perpendicular component has no effect on normals.
69
// 3. The parallel component changes the length of |SX| by the factor of a=(|SX|-|Vpar|)/|SX| (where the length
70
//    can be negative depending on the direction)
71
// 4. that in turn leaves the x and y parts of the normal unchanged and multiplies the z component by a!
72
//
73 353f7580 Leszek Koltunski
// |Vpar| = (Vx*dx-Vy*dy) / sqrt(ps_sq)  (-Vy because y is inverted)
74 7cd24173 leszek
// 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
75
//
76
// Side of the bubble
77
//
78
// choose from one of the three bubble shapes: the cone, the thin bubble and the thick bubble
79
// Case 1:
80 353f7580 Leszek Koltunski
// f(t) = t, i.e. f(x) = Vz * x/|SX|   (a cone)
81
// -|PS|/f'(|PX|) = -|PS|*|SX|/Vz but since ps_sq=|PS|^2 and d=|PX|/|SX| then |PS|*|SX| = ps_sq/(1-d)
82
// so finally -|PS|/f'(|PX|) = -ps_sq/(Vz*(1-d))
83 7cd24173 leszek
//
84
// Case 2:
85
// f(t) = 3t^2 - 2t^3 --> f(0)=0, f'(0)=0, f'(1)=0, f(1)=1 (the bell curve)
86 353f7580 Leszek Koltunski
// here we have t = x/|SX| which makes f'(|PX|) = 6*Vz*|PS|*|PX|/|SX|^3.
87
// so -|PS|/f'(|PX|) = (-|SX|^3)/(6Vz|PX|) =  (-|SX|^2) / (6*Vz*d) but
88 7cd24173 leszek
// d = |PX|/|SX| and ps_sq = |PS|^2 so |SX|^2 = ps_sq/(1-d)^2
89 353f7580 Leszek Koltunski
// so finally -|PS|/f'(|PX|) = -ps_sq/ (6Vz*d*(1-d)^2)
90 7cd24173 leszek
//
91
// Case 3:
92
// 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,
93
// f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!
94 353f7580 Leszek Koltunski
// then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12Vz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!)
95
// so finally -|PS|/f'(|PX|) = -ps_sq/ (12Vz*d*(1-d)^3)
96 7cd24173 leszek
//
97
// Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.
98
// 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 ).
99
// 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)
100
// 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
101
// can simply add up the first and second components.
102
//
103 353f7580 Leszek Koltunski
// Thus we actually want to compute N(Px,Py) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding
104 7cd24173 leszek
// the first two components. (a is the horizontal part)
105 353f7580 Leszek Koltunski
//
106
// 2019-01-09 fixes for stuff discovered with the Earth testing app
107
// Now, the above stuff works only if the normal vector is close to (0,0,1). To make it work for any situation,
108
// rotate the normal, force and ps vectors along the axis (n.y,-n.x,0) and angle A between the normal and (0,0,1)
109
// then modify the rotated normal (so (0,0,1)) and rotate the modified normal back.
110
//
111
// if we have a vector (vx,vy,vz) that w want to rotate with a rotation that turns the normal into (0,0,1), then
112
// a) axis of rotation = (n.x,n.y,n.z) x (0,0,1) = (n.y,-n.x,0)
113
// b) angle of rotation A: cosA = (n.x,n.y,n.z)*(0,0,1) = n.z     (and sinA = + sqrt(1-n.z^2))
114
//
115
// so normalized axisNor = (n.x/ sinA, -n.y/sinA, 0) and now from Rodrigues rotation formula
116
// Vrot = v*cosA + (axisNor x v)*sinA + axisNor*(axis*v)*(1-cosA)
117
//
118
// which makes Vrot = (a+n.y*c , b-n.y*c , v*n) where
119
// a = vx*nz-vz*nx , b = vy*nz-vz*ny , c = (vx*ny-vy*nx)/(1+nz)    (unless n=(0,0,-1))
120 faa3ff56 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
121
/**
122 7602a827 Leszek Koltunski
 * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
123 faa3ff56 Leszek Koltunski
 */
124 7cd24173 leszek
  public static void enable()
125
    {
126
    addEffect(EffectName.DISTORT,
127
128 0f10a0b6 Leszek Koltunski
        "vec3 ps = vUniforms[effect+1].yzw - v;                        \n"
129 353f7580 Leszek Koltunski
      + "vec3 force = vUniforms[effect].xyz;                           \n"
130
      + "vec4 region= vUniforms[effect+2];                             \n"
131 0f10a0b6 Leszek Koltunski
      + "float d = degree(region,ps);                                  \n"
132 353f7580 Leszek Koltunski
133
      + "if( d>0.0 )                                                   \n"
134
      + "  {                                                           \n"
135
      + "  v += d*force;                                               \n"
136 7cd24173 leszek
137 353f7580 Leszek Koltunski
      + "  float tp = 1.0+n.z;                                         \n"
138
      + "  float tr = 1.0 / (tp - (1.0 - sign(tp)));                   \n"
139 7cd24173 leszek
140 353f7580 Leszek Koltunski
      + "  float ap = ps.x*n.z - ps.z*n.x;                             \n"   // likewise rotate the ps vector
141
      + "  float bp = ps.y*n.z - ps.z*n.y;                             \n"   //
142
      + "  float cp =(ps.x*n.y - ps.y*n.x)*tr;                         \n"   //
143
      + "  vec3 psRot = vec3( ap+n.y*cp , bp-n.x*cp , dot(ps,n) );     \n"   //
144 7cd24173 leszek
145 50be8733 Leszek Koltunski
      + "  float len = length(psRot);                                  \n"
146
      + "  float corr= sign(len)-1.0;                                  \n"   // make N (0,0,1) if ps=(0,0,0)
147
      + "  vec3 N = vec3( -dot(force,n)*psRot.xy, region.w*len-corr ); \n"   // modified rotated normal
148 353f7580 Leszek Koltunski
                                                                             // dot(force,n) is rotated force.z
149
      + "  float an = N.x*n.z + N.z*n.x;                               \n"   // now create the normal vector
150
      + "  float bn = N.y*n.z + N.z*n.y;                               \n"   // back from our modified normal
151
      + "  float cn =(N.x*n.y - N.y*n.x)*tr;                           \n"   // rotated back
152
      + "  n = vec3( an+n.y*cn , bn-n.x*cn , -N.x*n.x-N.y*n.y+N.z*n.z);\n"   // notice 4 signs change!
153 7cd24173 leszek
154 353f7580 Leszek Koltunski
      + "  n = normalize(n);                                           \n"
155
      + "  }                                                           \n"
156 7cd24173 leszek
      );
157
    }
158 faa3ff56 Leszek Koltunski
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160
/**
161 6b816678 Leszek Koltunski
 * Distort a (possibly changing in time) part of the Mesh by a (possibly changing in time) vector of force.
162 faa3ff56 Leszek Koltunski
 *
163
 * @param vector vector of force the Center of the Effect is currently being dragged with.
164
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
165
 * @param region Region that masks the Effect.
166
 */
167
  public VertexEffectDistort(Data3D vector, Data3D center, Data4D region)
168
    {
169
    super(EffectName.DISTORT);
170
    mVector = vector;
171
    mCenter = center;
172 dd89c7f4 Leszek Koltunski
    mRegion = (region==null ? MAX_REGION : region);
173 faa3ff56 Leszek Koltunski
    }
174
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176
/**
177 6b816678 Leszek Koltunski
 * Distort the whole Mesh by a (possibly changing in time) vector of force.
178 faa3ff56 Leszek Koltunski
 *
179
 * @param vector vector of force the Center of the Effect is currently being dragged with.
180
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
181
 */
182
  public VertexEffectDistort(Data3D vector, Data3D center)
183
    {
184
    super(EffectName.DISTORT);
185
    mVector = vector;
186
    mCenter = center;
187 dd89c7f4 Leszek Koltunski
    mRegion = MAX_REGION;
188 faa3ff56 Leszek Koltunski
    }
189 125cee3d Leszek Koltunski
  }
190 15aa7d94 Leszek Koltunski