Project

General

Profile

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

library / src / main / java / org / distorted / library / effect / VertexEffectDistort.java @ b24e4719

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.Static4D;
25

    
26
///////////////////////////////////////////////////////////////////////////////////////////////////
27
/**
28
 * Distort the Mesh by applying a 3D vector of force.
29
 */
30
public class VertexEffectDistort extends VertexEffect
31
  {
32
  private Data3D mVector, mCenter;
33
  private Data4D mRegion;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36
/**
37
 * Only for use by the library itself.
38
 *
39
 * @y.exclude
40
 */
41
  public boolean compute(float[] uniforms, int index, long currentDuration, long step )
42
    {
43
    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
44
    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
45
    boolean ret = mVector.get(uniforms,index,currentDuration,step);
46

    
47
    uniforms[index+1] =-uniforms[index+1];
48
    uniforms[index+REGION_OFFSET+1] =-uniforms[index+REGION_OFFSET+1];  // region's y
49

    
50
    return ret;
51
    }
52

    
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54
// PUBLIC API
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56
// Point (Px,Py) gets moved by vector (Wx,Wy,Wz) where Wx/Wy = Vx/Vy i.e. Wx=aVx and Wy=aVy where
57
// 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)
58
// 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) ]
59
// Computations above are valid for screen (0,0)x(w,h) but here we have (-w/2,-h/2)x(w/2,h/2)
60
//
61
// the vertical part
62
// Let |(v.x,v.y),(ux,uy)| = |PS|, ux-v.x=dx,uy-v.y=dy, f(x) (0<=x<=|SX|) be the shape of the side of the bubble.
63
// H(v.x,v.y) = |PS|>|SX| ? 0 : f(|PX|)
64
// N(v.x,v.y) = |PS|>|SX| ? (0,0,1) : ( -(dx/|PS|)sin(beta), -(dy/|PS|)sin(beta), cos(beta) ) where tan(beta) is f'(|PX|)
65
// ( i.e. normalize( dx, dy, -|PS|/f'(|PX|))
66
//
67
// Now we also have to take into account the effect horizontal move by V=(u_dVx[i],u_dVy[i]) will have on the normal vector.
68
// Solution:
69
// 1. Decompose the V into two subcomponents, one parallel to SX and another perpendicular.
70
// 2. Convince yourself (draw!) that the perpendicular component has no effect on normals.
71
// 3. The parallel component changes the length of |SX| by the factor of a=(|SX|-|Vpar|)/|SX| (where the length
72
//    can be negative depending on the direction)
73
// 4. that in turn leaves the x and y parts of the normal unchanged and multiplies the z component by a!
74
//
75
// |Vpar| = (u_dVx[i]*dx - u_dVy[i]*dy) / sqrt(ps_sq) = (Vx*dx-Vy*dy)/ sqrt(ps_sq)  (-Vy because y is inverted)
76
// 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
77
//
78
// Side of the bubble
79
//
80
// choose from one of the three bubble shapes: the cone, the thin bubble and the thick bubble
81
// Case 1:
82
// f(t) = t, i.e. f(x) = uz * x/|SX|   (a cone)
83
// -|PS|/f'(|PX|) = -|PS|*|SX|/uz but since ps_sq=|PS|^2 and d=|PX|/|SX| then |PS|*|SX| = ps_sq/(1-d)
84
// so finally -|PS|/f'(|PX|) = -ps_sq/(uz*(1-d))
85
//
86
// Case 2:
87
// f(t) = 3t^2 - 2t^3 --> f(0)=0, f'(0)=0, f'(1)=0, f(1)=1 (the bell curve)
88
// here we have t = x/|SX| which makes f'(|PX|) = 6*uz*|PS|*|PX|/|SX|^3.
89
// so -|PS|/f'(|PX|) = (-|SX|^3)/(6uz|PX|) =  (-|SX|^2) / (6*uz*d) but
90
// d = |PX|/|SX| and ps_sq = |PS|^2 so |SX|^2 = ps_sq/(1-d)^2
91
// so finally -|PS|/f'(|PX|) = -ps_sq/ (6uz*d*(1-d)^2)
92
//
93
// Case 3:
94
// 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,
95
// f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!
96
// then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12uz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!)
97
// so finally -|PS|/f'(|PX|) = -ps_sq/ (12uz*d*(1-d)^3)
98
//
99
// Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.
100
// 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 ).
101
// 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)
102
// 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
103
// can simply add up the first and second components.
104
//
105
// Thus we actually want to compute N(v.x,v.y) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding
106
// the first two components. (a is the horizontal part)
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108
/**
109
 * Have to call this before the shaders get compiled (i.e before Distorted.onCreate()) for the Effect to work.
110
 */
111
  public static void enable()
112
    {
113
    addEffect(EffectName.DISTORT,
114

    
115
        "vec3 center = vUniforms[effect+1].yzw; \n"
116
      + "vec3 ps = center-v.xyz; \n"
117
      + "vec3 force = vUniforms[effect].xyz; \n"
118
      + "float d = degree(vUniforms[effect+2],center,ps); \n"
119
      + "float denom = dot(ps+(1.0-d)*force,ps); \n"
120
      + "float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0)); \n"          // = denom==0 ? 1000:1/denom;
121

    
122
       //v.z += force.z*d;                                                        // cone
123
       //b = -(force.z*(1.0-d))*one_over_denom;                                   //
124

    
125
       //v.z += force.z*d*d*(3.0-2.0*d);                                          // thin bubble
126
       //b = -(6.0*force.z*d*(1.0-d)*(1.0-d))*one_over_denom;                     //
127

    
128
      + "v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0); \n"                            // thick bubble
129
      + "float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom; \n"  //
130

    
131
      + "v.xy += d*force.xy; \n"
132
      + "n.xy += n.z*b*ps.xy;"
133
      );
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
/**
138
 * Distort a (possibly changing in time) part of the Mesh by a (possibly changing in time) vector of force.
139
 *
140
 * @param vector vector of force the Center of the Effect is currently being dragged with.
141
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
142
 * @param region Region that masks the Effect.
143
 */
144
  public VertexEffectDistort(Data3D vector, Data3D center, Data4D region)
145
    {
146
    super(EffectName.DISTORT);
147
    mVector = vector;
148
    mCenter = center;
149
    mRegion = (region==null ? new Static4D(0,0,0, Float.MAX_VALUE) : region);
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153
/**
154
 * Distort the whole Mesh by a (possibly changing in time) vector of force.
155
 *
156
 * @param vector vector of force the Center of the Effect is currently being dragged with.
157
 * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
158
 */
159
  public VertexEffectDistort(Data3D vector, Data3D center)
160
    {
161
    super(EffectName.DISTORT);
162
    mVector = vector;
163
    mCenter = center;
164
    mRegion = new Static4D(0,0,0, Float.MAX_VALUE);
165
    }
166
  }
167

    
168

    
(22-22/26)