1 |
125cee3d
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
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 |
15aa7d94
|
Leszek Koltunski
|
import org.distorted.library.type.Static4D;
|
26 |
125cee3d
|
Leszek Koltunski
|
|
27 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
28 |
faa3ff56
|
Leszek Koltunski
|
/**
|
29 |
|
|
* Directional, sinusoidal wave effect.
|
30 |
|
|
*/
|
31 |
125cee3d
|
Leszek Koltunski
|
public class VertexEffectWave extends VertexEffect
|
32 |
|
|
{
|
33 |
0dd98279
|
Leszek Koltunski
|
private Data5D mWave;
|
34 |
|
|
private Data3D mCenter;
|
35 |
|
|
private Data4D mRegion;
|
36 |
|
|
|
37 |
125cee3d
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
38 |
6bb59aad
|
Leszek Koltunski
|
/**
|
39 |
faa3ff56
|
Leszek Koltunski
|
* Only for use by the library itself.
|
40 |
6bb59aad
|
Leszek Koltunski
|
*
|
41 |
faa3ff56
|
Leszek Koltunski
|
* @y.exclude
|
42 |
6bb59aad
|
Leszek Koltunski
|
*/
|
43 |
15aa7d94
|
Leszek Koltunski
|
public boolean compute(float[] uniforms, int index, long currentDuration, long step )
|
44 |
|
|
{
|
45 |
b24e4719
|
Leszek Koltunski
|
mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
|
46 |
|
|
mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
|
47 |
0dd98279
|
Leszek Koltunski
|
boolean ret = mWave.get(uniforms,index,currentDuration,step);
|
48 |
15aa7d94
|
Leszek Koltunski
|
|
49 |
|
|
uniforms[index+2] = (float)(Math.PI*uniforms[index+2]/180);
|
50 |
|
|
uniforms[index+3] = (float)(Math.PI*uniforms[index+3]/180);
|
51 |
|
|
uniforms[index+4] = (float)(Math.PI*uniforms[index+4]/180);
|
52 |
b24e4719
|
Leszek Koltunski
|
|
53 |
|
|
uniforms[index+REGION_OFFSET+1] =-uniforms[index+REGION_OFFSET+1]; // region's y
|
54 |
15aa7d94
|
Leszek Koltunski
|
|
55 |
|
|
return ret;
|
56 |
125cee3d
|
Leszek Koltunski
|
}
|
57 |
7cd24173
|
leszek
|
|
58 |
faa3ff56
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
59 |
|
|
// PUBLIC API
|
60 |
7cd24173
|
leszek
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
61 |
|
|
// Directional sinusoidal wave effect.
|
62 |
|
|
//
|
63 |
|
|
// This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) ) (*)
|
64 |
|
|
// i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
|
65 |
|
|
// point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
|
66 |
|
|
//
|
67 |
|
|
// In this case V is defined by angles A and B (sines and cosines of which are precomputed in
|
68 |
|
|
// EffectQueueVertex and passed in the uniforms).
|
69 |
|
|
// 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
|
70 |
|
|
// to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
|
71 |
|
|
//
|
72 |
|
|
// Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
|
73 |
|
|
//
|
74 |
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
75 |
|
|
// How to compute any generic effect of type (*)
|
76 |
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
77 |
|
|
//
|
78 |
|
|
// By definition, the vertices move by f(x,y)*V.
|
79 |
|
|
//
|
80 |
|
|
// Normals are much more complicated.
|
81 |
|
|
// Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
|
82 |
|
|
// Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
|
83 |
|
|
//
|
84 |
|
|
// Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
|
85 |
|
|
// has 2 tangent vectors given by
|
86 |
|
|
//
|
87 |
|
|
// SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx); (**)
|
88 |
|
|
// SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy); (***)
|
89 |
|
|
//
|
90 |
|
|
// and then obviously the normal N is given by N= SX x SY .
|
91 |
|
|
//
|
92 |
|
|
// We still need to remember the note from the distort function about adding up normals:
|
93 |
|
|
// we first need to 'normalize' the normals to make their third components equal, and then we
|
94 |
|
|
// simply add up the first and the second component while leaving the third unchanged.
|
95 |
|
|
//
|
96 |
|
|
// How to see facts (**) and (***) ? Briefly:
|
97 |
|
|
// a) compute the 2D analogon and conclude that in this case the tangent SX is given by
|
98 |
|
|
// SX = ( cosA*f'(x) +1, sinA*f'(x) ) (where A is the angle vector V makes with X axis )
|
99 |
|
|
// b) cut the resulting surface with plane P which
|
100 |
|
|
// - includes vector V
|
101 |
|
|
// - crosses plane XY along line parallel to X axis
|
102 |
|
|
// c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
|
103 |
|
|
// and our surface (I am talking about the tangent vector which belongs to P) is given by
|
104 |
|
|
// (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
|
105 |
|
|
//
|
106 |
|
|
// Matrix of rotation:
|
107 |
|
|
//
|
108 |
|
|
// |sinY| cosY
|
109 |
|
|
// -cosY |sinY|
|
110 |
|
|
//
|
111 |
|
|
// d) compute the above and see that this is equal precisely to SX from (**).
|
112 |
|
|
// e) repeat points b,c,d in direction Y and come up with (***).
|
113 |
|
|
//
|
114 |
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
115 |
|
|
// Note: we should avoid passing certain combinations of parameters to this function. One such known
|
116 |
|
|
// combination is ( A: small but positive, B: any, amplitude >= length ).
|
117 |
|
|
// In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
|
118 |
|
|
// amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
|
119 |
|
|
// very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
|
120 |
|
|
// points very dark)
|
121 |
|
|
//
|
122 |
|
|
// Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
|
123 |
faa3ff56
|
Leszek Koltunski
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
124 |
|
|
/**
|
125 |
|
|
* Have to call this before the shaders get compiled (i.e before Distorted.onCreate()) for the Effect to work.
|
126 |
|
|
*/
|
127 |
7cd24173
|
leszek
|
public static void enable()
|
128 |
|
|
{
|
129 |
|
|
addEffect(EffectName.WAVE,
|
130 |
|
|
|
131 |
4aa38649
|
Leszek Koltunski
|
"vec3 center = vUniforms[effect+1].yzw; \n"
|
132 |
7cd24173
|
leszek
|
+ "float amplitude = vUniforms[effect ].x; \n"
|
133 |
|
|
+ "float length = vUniforms[effect ].y; \n"
|
134 |
|
|
|
135 |
4aa38649
|
Leszek Koltunski
|
+ "vec3 ps = center - v.xyz; \n"
|
136 |
7cd24173
|
leszek
|
+ "float deg = amplitude*degree_region(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 |
4aa38649
|
Leszek Koltunski
|
+ "if( normal.z<=0.0 ) \n" // Why this bizarre thing rather than the straightforward
|
175 |
7cd24173
|
leszek
|
+ "{ \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 |
4aa38649
|
Leszek Koltunski
|
+ "n.y = (n.y*normal.z + n.z*normal.y); \n" // ? Because if we do the above, my Nexus4 crashes
|
184 |
7cd24173
|
leszek
|
+ "n.z = (n.z*normal.z); \n" // during shader compilation!
|
185 |
|
|
+ "} \n"
|
186 |
|
|
+ "}"
|
187 |
|
|
);
|
188 |
|
|
}
|
189 |
faa3ff56
|
Leszek Koltunski
|
|
190 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
191 |
|
|
/**
|
192 |
|
|
* Directional, sinusoidal wave effect.
|
193 |
|
|
*
|
194 |
|
|
* @param wave A 5-dimensional data structure describing the wave: first member is the amplitude,
|
195 |
|
|
* second is the wave length, third is the phase (i.e. when phase = PI/2, the sine
|
196 |
|
|
* wave at the center does not start from sin(0), but from sin(PI/2) ) and the next two
|
197 |
|
|
* describe the 'direction' of the wave.
|
198 |
|
|
* <p>
|
199 |
|
|
* Wave direction is defined to be a 3D vector of length 1. To define such vectors, we
|
200 |
f81ebc3f
|
Leszek Koltunski
|
* need 2 floats: thus the fourth member is the angle Alpha (in degrees) which the vector
|
201 |
|
|
* forms with the XY-plane, and the fifth is the angle Beta (again in degrees) which
|
202 |
faa3ff56
|
Leszek Koltunski
|
* the projection of the vector to the XY-plane forms with the Y-axis (counterclockwise).
|
203 |
|
|
* <p>
|
204 |
|
|
* <p>
|
205 |
|
|
* Example1: if Alpha = 90, Beta = 90, (then V=(0,0,1) ) and the wave acts 'vertically'
|
206 |
|
|
* in the X-direction, i.e. cross-sections of the resulting surface with the XZ-plane
|
207 |
|
|
* will be sine shapes.
|
208 |
|
|
* <p>
|
209 |
|
|
* Example2: if Alpha = 90, Beta = 0, the again V=(0,0,1) and the wave is 'vertical',
|
210 |
|
|
* but this time it waves in the Y-direction, i.e. cross sections of the surface and the
|
211 |
|
|
* YZ-plane with be sine shapes.
|
212 |
|
|
* <p>
|
213 |
|
|
* Example3: if Alpha = 0 and Beta = 45, then V=(sqrt(2)/2, -sqrt(2)/2, 0) and the wave
|
214 |
|
|
* is entirely 'horizontal' and moves point (x,y,0) in direction V by whatever is the
|
215 |
|
|
* value if sin at this point.
|
216 |
|
|
* @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
|
217 |
|
|
* @param region Region that masks the Effect.
|
218 |
|
|
*/
|
219 |
|
|
public VertexEffectWave(Data5D wave, Data3D center, Data4D region)
|
220 |
|
|
{
|
221 |
|
|
super(EffectName.WAVE);
|
222 |
|
|
mWave = wave;
|
223 |
|
|
mCenter = center;
|
224 |
1f2cb152
|
Leszek Koltunski
|
mRegion = (region==null ? new Static4D(0,0,0, Float.MAX_VALUE) : region);
|
225 |
faa3ff56
|
Leszek Koltunski
|
}
|
226 |
|
|
|
227 |
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
228 |
|
|
/**
|
229 |
|
|
* Directional, sinusoidal wave effect.
|
230 |
|
|
*
|
231 |
6ba8be09
|
Leszek Koltunski
|
* @param wave see {@link #VertexEffectWave(Data5D,Data3D)}
|
232 |
faa3ff56
|
Leszek Koltunski
|
* @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
|
233 |
|
|
*/
|
234 |
|
|
public VertexEffectWave(Data5D wave, Data3D center)
|
235 |
|
|
{
|
236 |
|
|
super(EffectName.WAVE);
|
237 |
|
|
mWave = wave;
|
238 |
|
|
mCenter = center;
|
239 |
4aa38649
|
Leszek Koltunski
|
mRegion = new Static4D(0,0,0, Float.MAX_VALUE);
|
240 |
faa3ff56
|
Leszek Koltunski
|
}
|
241 |
125cee3d
|
Leszek Koltunski
|
}
|