transform.glsl (4996B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 flat varying highp vec4 vTransformBounds; 6 7 #ifdef WR_VERTEX_SHADER 8 9 #define VECS_PER_TRANSFORM 8U 10 uniform HIGHP_SAMPLER_FLOAT sampler2D sTransformPalette; 11 12 void rectangle_aa_vertex(vec4 local_bounds) { 13 vTransformBounds = local_bounds; 14 } 15 16 struct Transform { 17 mat4 m; 18 mat4 inv_m; 19 bool is_axis_aligned; 20 }; 21 22 Transform fetch_transform(int id) { 23 Transform transform; 24 25 transform.is_axis_aligned = (id >> 23) == 0; 26 int index = id & 0x007fffff; 27 28 // Create a UV base coord for each 8 texels. 29 // This is required because trying to use an offset 30 // of more than 8 texels doesn't work on some versions 31 // of macOS. 32 ivec2 uv = get_fetch_uv(index, VECS_PER_TRANSFORM); 33 ivec2 uv0 = ivec2(uv.x + 0, uv.y); 34 35 transform.m[0] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(0, 0)); 36 transform.m[1] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(1, 0)); 37 transform.m[2] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(2, 0)); 38 transform.m[3] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(3, 0)); 39 40 transform.inv_m[0] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(4, 0)); 41 transform.inv_m[1] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(5, 0)); 42 transform.inv_m[2] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(6, 0)); 43 transform.inv_m[3] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(7, 0)); 44 45 return transform; 46 } 47 48 // Return the intersection of the plane (set up by "normal" and "point") 49 // with the ray (set up by "ray_origin" and "ray_dir"), 50 // writing the resulting scaler into "t". 51 bool ray_plane(vec3 normal, vec3 pt, vec3 ray_origin, vec3 ray_dir, out float t) 52 { 53 float denom = dot(normal, ray_dir); 54 if (abs(denom) > 1e-6) { 55 vec3 d = pt - ray_origin; 56 t = dot(d, normal) / denom; 57 return t >= 0.0; 58 } 59 60 return false; 61 } 62 63 // Apply the inverse transform "inv_transform" 64 // to the reference point "ref" in CSS space, 65 // producing a local point on a Transform plane, 66 // set by a base point "a" and a normal "n". 67 vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) { 68 vec3 p = vec3(ref, -10000.0); 69 vec3 d = vec3(0, 0, 1.0); 70 71 float t = 0.0; 72 // get an intersection of the Transform plane with Z axis vector, 73 // originated from the "ref" point 74 ray_plane(n, a, p, d, t); 75 float z = p.z + d.z * t; // Z of the visible point on the Transform 76 77 vec4 r = inv_transform * vec4(ref, z, 1.0); 78 return r; 79 } 80 81 // Given a CSS space position, transform it back into the Transform space. 82 vec4 get_node_pos(vec2 pos, Transform transform) { 83 // get a point on the scroll node plane 84 vec4 ah = transform.m * vec4(0.0, 0.0, 0.0, 1.0); 85 vec3 a = ah.xyz / ah.w; 86 87 // get the normal to the scroll node plane 88 vec3 n = transpose(mat3(transform.inv_m)) * vec3(0.0, 0.0, 1.0); 89 return untransform(pos, n, a, transform.inv_m); 90 } 91 92 #endif //WR_VERTEX_SHADER 93 94 #ifdef WR_FRAGMENT_SHADER 95 96 // Assume transform bounds are set to a large scale to signal they are invalid. 97 bool has_valid_transform_bounds() { 98 return vTransformBounds.w < 1.0e15; 99 } 100 101 float rectangle_aa_fragment(vec2 local_pos) { 102 // Ideally we want to track distances in screen space after transformation 103 // as signed distance calculations lose context about the direction vector 104 // to exit the geometry, merely remembering the minimum distance to the 105 // exit. However, we can't always sanely track distances in screen space 106 // due to perspective transforms, clipping, and other concerns, so we do 107 // this in local space. However, this causes problems tracking distances 108 // in local space when attempting to scale by a uniform AA range later in 109 // the presence of a transform which actually has non-uniform scaling. 110 // 111 // To work around this, we independently track the distances on the local 112 // space X and Y axes and then scale them by the independent AA ranges (as 113 // computed from fwidth derivatives) for the X and Y axes. This can break 114 // down at certain angles (45 degrees or close to it), but still gives a 115 // better approximation of screen-space distances in the presence of non- 116 // uniform scaling for other rotations. 117 // 118 // Get signed distance from local rect bounds. 119 vec2 d = signed_distance_rect_xy( 120 local_pos, 121 vTransformBounds.xy, 122 vTransformBounds.zw 123 ); 124 125 // Find the appropriate distance to apply the AA smoothstep over. 126 vec2 aa_range = compute_aa_range_xy(local_pos); 127 128 // Only apply AA to fragments outside the signed distance field. 129 return distance_aa_xy(aa_range, d); 130 } 131 132 float rectangle_aa_rough_fragment(vec2 local_pos) { 133 return point_inside_rect( 134 local_pos, 135 vTransformBounds.xy, 136 vTransformBounds.zw 137 ); 138 } 139 140 #endif //WR_FRAGMENT_SHADER