Project

General

Profile

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

library / src / main / java / org / distorted / library / effect / VertexEffectWave.java @ e5f796bc

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2017 Leszek Koltunski  leszek@koltunski.pl                                          //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// This library is free software; you can redistribute it and/or                                 //
7
// modify it under the terms of the GNU Lesser General Public                                    //
8
// License as published by the Free Software Foundation; either                                  //
9
// version 2.1 of the License, or (at your option) any later version.                            //
10
//                                                                                               //
11
// This library 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 GNU                             //
14
// Lesser General Public License for more details.                                               //
15
//                                                                                               //
16
// You should have received a copy of the GNU Lesser General Public                              //
17
// License along with this library; if not, write to the Free Software                           //
18
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
19
///////////////////////////////////////////////////////////////////////////////////////////////////
20

    
21
package org.distorted.library.effect;
22

    
23
import org.distorted.library.type.Data3D;
24
import org.distorted.library.type.Data4D;
25
import org.distorted.library.type.Data5D;
26

    
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28
/**
29
 * Directional, sinusoidal wave effect.
30
 *
31
 * Not a fully 3D effect. To achieve a fully 3D one we'd need another parameter making the whole thing
32
 * a 6D effect but there's no room in the Vertex Uniforms which assign only 5 floats for interpolated
33
 * effect values. Rethink this. ATM fully enough for 2.5D meshes like the MeshCubes.
34
 */
35
public class VertexEffectWave extends VertexEffect
36
  {
37
  private static final EffectName NAME = EffectName.WAVE;
38

    
39
  private final Data5D mWave;
40
  private final Data3D mCenter;
41
  private final Data4D mRegion;
42

    
43
///////////////////////////////////////////////////////////////////////////////////////////////////
44
/**
45
 * Only for use by the library itself.
46
 *
47
 * @y.exclude
48
 */
49
  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
50
    {
51
    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
52
    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
53
    boolean ret = mWave.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
54

    
55
    uniforms[index+VALUES_OFFSET+2] = (float)(Math.PI*uniforms[index+VALUES_OFFSET+2]/180);
56
    uniforms[index+VALUES_OFFSET+3] = (float)(Math.PI*uniforms[index+VALUES_OFFSET+3]/180);
57
    uniforms[index+VALUES_OFFSET+4] = (float)(Math.PI*uniforms[index+VALUES_OFFSET+4]/180);
58

    
59
    return ret;
60
    }
61

    
62
//////////////////////////////////////////////////////////////////////////////////////////////
63
// Directional sinusoidal wave effect.
64
//
65
// This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) )  (*)
66
// i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
67
// point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
68
//
69
// In this case V is defined by angles A and B (sines and cosines of which are precomputed in
70
// EffectQueueVertex and passed in the uniforms).
71
// 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
72
// to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
73
//
74
// Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
75
//
76
//////////////////////////////////////////////////////////////////////////////////////////////
77
// How to compute any generic effect of type (*)
78
//////////////////////////////////////////////////////////////////////////////////////////////
79
//
80
// By definition, the vertices move by f(x,y)*V.
81
//
82
// Normals are much more complicated.
83
// Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
84
// Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
85
//
86
// Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
87
// has 2 tangent vectors given by
88
//
89
// SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx);  (**)
90
// SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy);  (***)
91
//
92
// and then obviously the normal N is given by N= SX x SY .
93
//
94
// We still need to remember the note from the distort function dialog_about adding up normals:
95
// we first need to 'normalize' the normals to make their third components equal, and then we
96
// simply add up the first and the second component while leaving the third unchanged.
97
//
98
// How to see facts (**) and (***) ? Briefly:
99
// a) compute the 2D analogon and conclude that in this case the tangent SX is given by
100
//    SX = ( cosA*f'(x) +1, sinA*f'(x) )    (where A is the angle vector V makes with X axis )
101
// b) cut the resulting surface with plane P which
102
//    - includes vector V
103
//    - crosses plane XY along line parallel to X axis
104
// c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
105
//    and our surface (I am talking dialog_about the tangent vector which belongs to P) is given by
106
//    (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
107
//
108
//    Matrix of rotation:
109
//
110
//    |sinY|  cosY
111
//    -cosY  |sinY|
112
//
113
// d) compute the above and see that this is equal precisely to SX from (**).
114
// e) repeat points b,c,d in direction Y and come up with (***).
115
//
116
//////////////////////////////////////////////////////////////////////////////////////////////
117
// Note: we should avoid passing certain combinations of parameters to this function. One such known
118
// combination is ( A: small but positive, B: any, amplitude >= length ).
119
// In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
120
// amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
121
// very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
122
// points very dark)
123
//
124
// Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

    
127
  static String code()
128
    {
129
    return
130

    
131
        "vec3 center     = vUniforms[effect+1].yzw;                   \n"
132
      + "float amplitude = vUniforms[effect  ].x;                     \n"
133
      + "float length    = vUniforms[effect  ].y;                     \n"
134

    
135
      + "vec3 ps = center - v;                                        \n"
136
      + "float deg = amplitude*degree(vUniforms[effect+2],ps);        \n"
137

    
138
      + "if( deg != 0.0 && length != 0.0 )                            \n"
139
      +   "{                                                          \n"
140
      +   "float phase = vUniforms[effect  ].z;                       \n"
141
      +   "float alpha = vUniforms[effect  ].w;                       \n"
142
      +   "float beta  = vUniforms[effect+1].x;                       \n"
143

    
144
      +   "float sinA = sin(alpha);                                   \n"
145
      +   "float cosA = cos(alpha);                                   \n"
146
      +   "float sinB = sin(beta);                                    \n"
147
      +   "float cosB = cos(beta);                                    \n"
148

    
149
      +   "float angle= 1.578*(ps.x*cosB-ps.y*sinB) / length + phase; \n"
150
      +   "vec3 dir= vec3(sinB*cosA,cosB*cosA,sinA);                  \n"
151
      +   "v += sin(angle)*deg*dir;                                   \n"
152

    
153
      +   "if( n.z != 0.0 )                                           \n"
154
      +     "{                                                        \n"
155
      +     "float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z);           \n"
156
      +     "float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z);           \n"
157

    
158
      +     "float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY);        \n"
159
      +     "float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY);        \n"
160
      +     "float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX);        \n"
161
      +     "float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX);        \n"
162

    
163
      +     "float abs_z = dir.z <0.0 ? -(sinX*sinY) : (sinX*sinY);   \n"
164
      +     "float tmp = 1.578*cos(angle)*deg/length;                 \n"
165

    
166
      +     "float fx =-cosB*tmp;                                     \n"
167
      +     "float fy = sinB*tmp;                                     \n"
168

    
169
      +     "vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,abs_z*fx);      \n"
170
      +     "vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,abs_z*fy);      \n"
171

    
172
      +     "vec3 normal = cross(sx,sy);                              \n"
173

    
174
      +     "if( normal.z<=0.0 )                                      \n"   // Why this bizarre thing rather than the straightforward
175
      +       "{                                                      \n"   //
176
      +       "normal.x= 0.0;                                         \n"   // if( normal.z>0.0 )
177
      +       "normal.y= 0.0;                                         \n"   //   {
178
      +       "normal.z= 1.0;                                         \n"   //   n.x = (n.x*normal.z + n.z*normal.x);
179
      +       "}                                                      \n"   //   n.y = (n.y*normal.z + n.z*normal.y);
180
                                                                            //   n.z = (n.z*normal.z);
181
                                                                            //   }
182
      +     "n.x = (n.x*normal.z + n.z*normal.x);                     \n"   //
183
      +     "n.y = (n.y*normal.z + n.z*normal.y);                     \n"   // ? Because if we do the above, my Nexus4 crashes
184
      +     "n.z = (n.z*normal.z);                                    \n"   // during shader compilation!
185
      +     "n = normalize(n);                                        \n"
186
      +     "}                                                        \n"
187
      +   "}";
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191
// PUBLIC API
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193
/**
194
 * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
195
 */
196
  public static void enable()
197
    {
198
    addEffect( NAME, code() );
199
    }
200

    
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202
/**
203
 * Directional, sinusoidal wave effect.
204
 *
205
 * @param wave   A 5-dimensional data structure describing the wave: first member is the amplitude,
206
 *               second is the wave length, third is the phase (i.e. when phase = PI/2, the sine
207
 *               wave at the center does not start from sin(0), but from sin(PI/2) ) and the next two
208
 *               describe the 'direction' of the wave.
209
 *               <p>
210
 *               Wave direction is defined to be a 3D vector of length 1. To define such vectors, we
211
 *               need 2 floats: thus the fourth member is the angle Alpha (in degrees) which the vector
212
 *               forms with the XY-plane, and the fifth is the angle Beta (again in degrees) which
213
 *               the projection of the vector to the XY-plane forms with the Y-axis (counterclockwise).
214
 *               <p>
215
 *               <p>
216
 *               Example1: if Alpha = 90, Beta = 90, (then V=(0,0,1) ) and the wave acts 'vertically'
217
 *               in the X-direction, i.e. cross-sections of the resulting surface with the XZ-plane
218
 *               will be sine shapes.
219
 *               <p>
220
 *               Example2: if Alpha = 90, Beta = 0, the again V=(0,0,1) and the wave is 'vertical',
221
 *               but this time it waves in the Y-direction, i.e. cross sections of the surface and the
222
 *               YZ-plane with be sine shapes.
223
 *               <p>
224
 *               Example3: if Alpha = 0 and Beta = 45, then V=(sqrt(2)/2, sqrt(2)/2, 0) and the wave
225
 *               is entirely 'horizontal' and moves point (x,y,0) in direction V by whatever is the
226
 *               value if sin at this point.
227
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
228
 * @param region Region that masks the Effect.
229
 */
230
  public VertexEffectWave(Data5D wave, Data3D center, Data4D region)
231
    {
232
    super(NAME);
233
    mWave   = wave;
234
    mCenter = center;
235
    mRegion = (region==null ? MAX_REGION : region);
236
    }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239
/**
240
 * Directional, sinusoidal wave effect.
241
 *
242
 * @param wave   see {@link #VertexEffectWave(Data5D,Data3D,Data4D)}
243
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
244
 */
245
  public VertexEffectWave(Data5D wave, Data3D center)
246
    {
247
    super(NAME);
248
    mWave   = wave;
249
    mCenter = center;
250
    mRegion = MAX_REGION;
251
    }
252
  }
(34-34/34)