2 * The common parameters for all the vertices, calculate in CPU then pass into the shader as uniforms
4 * first part of the page, (outside the the line passing through original center and vertical to curve direction)
5 * no Z change, only 2D rotation and translation
6 * ([0][0],[0][1],[1][0],[1][1]) mat2 rotateMatrix
7 * ([2][0],[2][1]) vec2 translationVector
9 * ([0][2],[0][3]) vec2 originalCenter: Typically the press down position of the Pan Gesture
10 * ([1][2],[1][3]) vec2 currentCenter: Typically the current position of the Pan Gesture
11 * ([3][0],[3][1]) vec2 curveDirection: The normalized vector pointing from original center to current center
12 * ([2][2]) float vanishingPointY: The Y coordinate of the intersection of the spine
13 * and the line which goes through the original center and is vertical to the curveDirection
14 * ([2][3]) float curveEndY: The Y coordinate of intersection of the spine and the line through both original and current center
15 * ([3][2]) float curveHeight: The height of the interpolated hermite curve.
16 * ([3][3]) float currentLength: The length from the current center to the curveEnd.
19 precision mediump float;
21 attribute mediump vec2 aPosition;
23 uniform mediump mat4 uMvpMatrix;
24 uniform mediump mat3 uNormalMatrix;
25 uniform mediump mat4 uModelView;
27 uniform mat4 uCommonParameters;
30 uniform float uIsTurningBack;
31 uniform float uTextureWidth;
33 varying vec4 vPosition;
34 varying mediump vec2 vTexCoord;
38 vec4 position = vec4( aPosition*uSize.xy, 0.0, 1.0);
39 vec2 currentCenter = vec2( uCommonParameters[1][2], uCommonParameters[1][3]);
40 vec2 originalCenter = vec2( uCommonParameters[0][2], uCommonParameters[0][3]);
41 vec3 normal = vec3(0.0,0.0,1.0);
43 if(currentCenter.x < originalCenter.x)
45 // change the coordinate origin from the center of the page to its top-left
46 position.xy += uSize.xy * 0.5;
47 vec2 curveDirection = vec2( uCommonParameters[3]);
48 vec3 vanishingPoint = vec3(0.0, uCommonParameters[2][2], 0.0);
49 // first part of the page, (outside the the line passing through original center and vertical to curve direction)
50 //no Z change, only 2D rotation and translation
51 if( dot(curveDirection, position.xy - originalCenter) < 0.0 )
53 position.y -= vanishingPoint.y;
54 position.xy = mat2(uCommonParameters)*position.xy + vec2( uCommonParameters[2]);
56 // second part of the page, bent as a ruled surface
59 // calculate on the flat plane, between
60 // the first line passing through current vertex and vanishing point
61 // the second line passing through original center and current center
62 vec2 curveEnd = vec2( 0.0, uCommonParameters[2][3] );
63 vec2 curFlatDirection = vec2(0.0,1.0);
64 float lengthFromCurve = position.y - originalCenter.y;
65 float lengthOnCurve = position.x;
66 if(currentCenter.y != originalCenter.y)
68 curFlatDirection = normalize(position.xy - vanishingPoint.xy);
69 lengthFromCurve = (curveEnd.x*curveDirection.y-curveEnd.y*curveDirection.x-position.x*curveDirection.y+position.y*curveDirection.x)
70 / (curFlatDirection.x*curveDirection.y-curFlatDirection.y*curveDirection.x);
71 lengthOnCurve = length(position.xy+lengthFromCurve*curFlatDirection-curveEnd);
74 // define the control points of hermite curve, composed with two segments
75 // calculation is carried out on the 2D plane which is passing through both current and original center and vertical to the image plane
76 float currentLength = uCommonParameters[3][3];
77 float originalLength = abs(originalCenter.x/curveDirection.x);
78 float height = uCommonParameters[3][2];
79 float percentage = currentLength/originalLength;
80 //vec2 SegmentOneControlPoint0 = vec2(0.0, 0.0);
81 vec2 SegmentOneControlPoint1 = vec2((0.65*percentage - 0.15)*originalLength, (0.8 + 0.2 * percentage)*height);
82 vec2 SegmentTwoControlPoint0 = SegmentOneControlPoint1;
83 vec2 SegmentTwoControlPoint1 = vec2(currentLength, 0.0);
84 vec2 SegmentOneTangentVector0 = SegmentOneControlPoint1;
85 vec2 SegmentOneTangentVector1 = vec2(0.5*originalLength,0.0);
86 vec2 SegmentTwoTangentVector0 = SegmentOneTangentVector1;
87 vec2 SegmentTwoTangentVector1 = SegmentOneTangentVector1;
89 // calculate the corresponding curve point position and its tangent vector
90 // it is a linear mapping onto nonlinear curves, might cause some unwanted deformation
91 // but as there are no analytical method to calculate the curve length on arbitrary segment
92 // no efficient way to solve this nonlinear mapping, Numerical approximation would cost too much computation in shader
95 float t0 = lengthOnCurve / originalLength;
101 curvePoint2D = (-2.0*t_3+3.0*t_2)*SegmentOneControlPoint1
102 + (t_3-2.0*t_2+t)*SegmentOneTangentVector0 + (t_3-t_2)*SegmentOneTangentVector1;
103 tangent = (-6.0*t_2+6.0*t)*SegmentOneControlPoint1
104 + (3.0*t_2-4.0*t+1.0)*SegmentOneTangentVector0 + (3.0*t_2-2.0*t)*SegmentOneTangentVector1;
108 float t = 2.0*t0-1.0;
111 curvePoint2D = (2.0*t_3-3.0*t_2+1.0)*SegmentTwoControlPoint0 + (-2.0*t_3+3.0*t_2)*SegmentTwoControlPoint1
112 + (t_3-2.0*t_2+t)*SegmentTwoTangentVector0 + (t_3-t_2)*SegmentTwoTangentVector1;
113 tangent = (6.0*t_2-6.0*t)*SegmentTwoControlPoint0 + (-6.0*t_2+6.0*t)*SegmentTwoControlPoint1
114 + (3.0*t_2-4.0*t+1.0)*SegmentTwoTangentVector0 + (3.0*t_2-2.0*t)*SegmentTwoTangentVector1;
115 // a trick to eliminate some optical illusion caused by the gradient matter of normal in per-fragment shading
116 // which is caused by linear interpolation of normal vs. nonlinear lighting
117 // will notice some artifact in the areas with dramatically normal changes, so compress the normal differences here
118 tangent.y *= min(1.0, length(position.xyz - vanishingPoint) / uSize.y );
120 vec3 curvePoint = vec3(curveEnd - curvePoint2D.x*curveDirection,max(0.0,curvePoint2D.y));
121 vec3 tangentVector = vec3(-tangent.x*curveDirection,tangent.y);
123 // locate the new vertex position on the line passing through both vanishing point and the calculated curve point position
124 vec3 curLiftDirection = vec3(0.0,-1.0,0.0);
125 if(currentCenter.y != originalCenter.y)
127 curLiftDirection = normalize(curvePoint - vanishingPoint);
128 tangentVector *= (curveDirection.y > 0.0) ? -1.0 : 1.0;
129 // an heuristic adjustment here, to compensate the linear parameter mapping onto the nonlinear curve
130 float Y0 = position.y - curveDirection.y * (position.x/curveDirection.x);
133 if(abs(Y0-vanishingPoint.y) > abs(curveEnd.y-vanishingPoint.y))
135 proportion = abs(curveEnd.y - Y0) / (abs(curveEnd.y-Y0)+abs(curveEnd.y - vanishingPoint.y));
136 refLength = proportion*length(originalCenter-vanishingPoint.xy) / (proportion-1.0);
140 proportion = abs(curveEnd.y - Y0) / abs(curveEnd.y - vanishingPoint.y);
141 refLength = proportion*length(originalCenter-vanishingPoint.xy);
143 float Y1 = currentCenter.y - (normalize(currentCenter-vanishingPoint.xy)).y * refLength;
144 position.y = mix(Y0, Y1, t0);
146 position.xz = curvePoint.xz - lengthFromCurve*curLiftDirection.xz;
147 // calculate the normal vector, will be used for lighting
148 normal = cross(curLiftDirection, normalize(tangentVector));
149 // the signature of Z is decided by the page turning direction:
150 // from left to right(negative); from right to left (positive)
151 position.z *= -uIsTurningBack;
152 normal.xy *= -uIsTurningBack;
154 // change the coordinate origin from the top-left of the page to its center
155 position.xy -= uSize.xy * 0.5;
157 vNormal = uNormalMatrix * normal;
158 gl_Position = uMvpMatrix * position;
159 // varying parameters for fragment shader
160 vTexCoord = aPosition + vec2(0.5);
161 vTexCoord.x /= uTextureWidth;
162 vPosition = uModelView * position;