Project

General

Profile

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

library / src / main / java / org / distorted / library / effect / VertexEffectWave.java @ 041b6dee

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2017 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
package org.distorted.library.effect;
21

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

    
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28

    
29
public class VertexEffectWave extends VertexEffect
30
  {
31
  private Data5D mWave;
32
  private Data3D mCenter;
33
  private Data4D mRegion;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
/**
37
 * Directional, sinusoidal wave effect.
38
 *
39
 * @param wave   A 5-dimensional data structure describing the wave: first member is the amplitude,
40
 *               second is the wave length, third is the phase (i.e. when phase = PI/2, the sine
41
 *               wave at the center does not start from sin(0), but from sin(PI/2) ) and the next two
42
 *               describe the 'direction' of the wave.
43
 *               <p>
44
 *               Wave direction is defined to be a 3D vector of length 1. To define such vectors, we
45
 *               need 2 floats: thus the third member is the angle Alpha (in degrees) which the vector
46
 *               forms with the XY-plane, and the fourth is the angle Beta (again in degrees) which
47
 *               the projection of the vector to the XY-plane forms with the Y-axis (counterclockwise).
48
 *               <p>
49
 *               <p>
50
 *               Example1: if Alpha = 90, Beta = 90, (then V=(0,0,1) ) and the wave acts 'vertically'
51
 *               in the X-direction, i.e. cross-sections of the resulting surface with the XZ-plane
52
 *               will be sine shapes.
53
 *               <p>
54
 *               Example2: if Alpha = 90, Beta = 0, the again V=(0,0,1) and the wave is 'vertical',
55
 *               but this time it waves in the Y-direction, i.e. cross sections of the surface and the
56
 *               YZ-plane with be sine shapes.
57
 *               <p>
58
 *               Example3: if Alpha = 0 and Beta = 45, then V=(sqrt(2)/2, -sqrt(2)/2, 0) and the wave
59
 *               is entirely 'horizontal' and moves point (x,y,0) in direction V by whatever is the
60
 *               value if sin at this point.
61
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
62
 * @param region Region that masks the Effect.
63
 */
64
  public VertexEffectWave(Data5D wave, Data3D center, Data4D region)
65
    {
66
    super(EffectName.WAVE);
67
    mWave   = wave;
68
    mCenter = center;
69
    mRegion = (region==null ? new Static4D(0,0,Float.MAX_VALUE, Float.MAX_VALUE) : region);
70
    }
71

    
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73
/**
74
 * Directional, sinusoidal wave effect.
75
 *
76
 * @param wave   see {@link VertexEffectWave(Data5D,Data3D)}
77
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
78
 */
79
  public VertexEffectWave(Data5D wave, Data3D center)
80
    {
81
    super(EffectName.WAVE);
82
    mWave   = wave;
83
    mCenter = center;
84
    mRegion = new Static4D(0,0,Float.MAX_VALUE, Float.MAX_VALUE);
85
    }
86

    
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

    
89
  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
90
    {
91
    mCenter.get(uniforms,index+5,currentDuration,step);
92
    mRegion.get(uniforms,index+8,currentDuration,step);
93
    boolean ret = mWave.get(uniforms,index,currentDuration,step);
94

    
95
    uniforms[index+2] = (float)(Math.PI*uniforms[index+2]/180);
96
    uniforms[index+3] = (float)(Math.PI*uniforms[index+3]/180);
97
    uniforms[index+4] = (float)(Math.PI*uniforms[index+4]/180);
98
    uniforms[index+9] =-uniforms[index+9];
99

    
100
    return ret;
101
    }
102

    
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104
// Directional sinusoidal wave effect.
105
//
106
// This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) )  (*)
107
// i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
108
// point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
109
//
110
// In this case V is defined by angles A and B (sines and cosines of which are precomputed in
111
// EffectQueueVertex and passed in the uniforms).
112
// 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
113
// to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
114
//
115
// Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
116
//
117
//////////////////////////////////////////////////////////////////////////////////////////////
118
// How to compute any generic effect of type (*)
119
//////////////////////////////////////////////////////////////////////////////////////////////
120
//
121
// By definition, the vertices move by f(x,y)*V.
122
//
123
// Normals are much more complicated.
124
// Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
125
// Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
126
//
127
// Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
128
// has 2 tangent vectors given by
129
//
130
// SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx);  (**)
131
// SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy);  (***)
132
//
133
// and then obviously the normal N is given by N= SX x SY .
134
//
135
// We still need to remember the note from the distort function about adding up normals:
136
// we first need to 'normalize' the normals to make their third components equal, and then we
137
// simply add up the first and the second component while leaving the third unchanged.
138
//
139
// How to see facts (**) and (***) ? Briefly:
140
// a) compute the 2D analogon and conclude that in this case the tangent SX is given by
141
//    SX = ( cosA*f'(x) +1, sinA*f'(x) )    (where A is the angle vector V makes with X axis )
142
// b) cut the resulting surface with plane P which
143
//    - includes vector V
144
//    - crosses plane XY along line parallel to X axis
145
// c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
146
//    and our surface (I am talking about the tangent vector which belongs to P) is given by
147
//    (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
148
//
149
//    Matrix of rotation:
150
//
151
//    |sinY|  cosY
152
//    -cosY  |sinY|
153
//
154
// d) compute the above and see that this is equal precisely to SX from (**).
155
// e) repeat points b,c,d in direction Y and come up with (***).
156
//
157
//////////////////////////////////////////////////////////////////////////////////////////////
158
// Note: we should avoid passing certain combinations of parameters to this function. One such known
159
// combination is ( A: small but positive, B: any, amplitude >= length ).
160
// In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
161
// amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
162
// very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
163
// points very dark)
164
//
165
// Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
166

    
167
  public static void enable()
168
    {
169
    addEffect(EffectName.WAVE,
170

    
171
        "vec2 center     = vUniforms[effect+1].yz; \n"
172
      + "float amplitude = vUniforms[effect  ].x; \n"
173
      + "float length    = vUniforms[effect  ].y; \n"
174

    
175
      + "vec2 ps = center - v.xy; \n"
176
      + "float deg = amplitude*degree_region(vUniforms[effect+2],ps); \n"
177

    
178
      + "if( deg != 0.0 && length != 0.0 ) \n"
179
      +   "{ \n"
180
      +   "float phase = vUniforms[effect  ].z; \n"
181
      +   "float alpha = vUniforms[effect  ].w; \n"
182
      +   "float beta  = vUniforms[effect+1].x; \n"
183

    
184
      +   "float sinA = sin(alpha); \n"
185
      +   "float cosA = cos(alpha); \n"
186
      +   "float sinB = sin(beta); \n"
187
      +   "float cosB = cos(beta); \n"
188

    
189
      +   "float angle= 1.578*(ps.x*cosB-ps.y*sinB) / length + phase; \n"
190
      +   "vec3 dir= vec3(sinB*cosA,cosB*cosA,sinA); \n"
191
      +   "v += sin(angle)*deg*dir; \n"
192

    
193
      +   "if( n.z != 0.0 ) \n"
194
      +     "{ \n"
195
      +     "float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z); \n"
196
      +     "float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z); \n"
197

    
198
      +     "float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY); \n"
199
      +     "float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY); \n"
200
      +     "float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX); \n"
201
      +     "float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX); \n"
202

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

    
206
      +     "float fx =-cosB*tmp; \n"
207
      +     "float fy = sinB*tmp; \n"
208

    
209
      +     "vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,abs_z*fx); \n"
210
      +     "vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,abs_z*fy); \n"
211

    
212
      +     "vec3 normal = cross(sx,sy); \n"
213

    
214
      +     "if( normal.z<=0.0 ) \n"                   // Why this bizarre shit rather than the straightforward
215
      +       "{ \n"                                   //
216
      +       "normal.x= 0.0; \n"                      // if( normal.z>0.0 )
217
      +       "normal.y= 0.0; \n"                      //   {
218
      +       "normal.z= 1.0; \n"                      //   n.x = (n.x*normal.z + n.z*normal.x);
219
      +       "} \n"                                   //   n.y = (n.y*normal.z + n.z*normal.y);
220
                                                       //   n.z = (n.z*normal.z);
221
                                                       //   }
222
      +     "n.x = (n.x*normal.z + n.z*normal.x); \n"  //
223
      +     "n.y = (n.y*normal.z + n.z*normal.y); \n"  // ? Because if we do the above, my shitty Nexus4 crashes
224
      +     "n.z = (n.z*normal.z); \n"                 // during shader compilation!
225
      +     "} \n"
226
      +   "}"
227
      );
228
    }
229
  }
(25-25/25)