I played around with shadertoy, adapting https://www.shadertoy.com/view/XsXSz4# to work with a quad to get the signed distance of an arbitrary quad in screen space. ```C float cross2(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } float quad_distance(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { // Vectors along each edge. vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p3 - p2; vec2 e3 = p0 - p3; // Vectors from the point to each vertex. vec2 v0 = p - p0; vec2 v1 = p - p1; vec2 v2 = p - p2; vec2 v3 = p - p3; vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); vec2 pq3 = v3 - e3 * clamp(dot(v3, e3) / dot(e3, e3), 0.0, 1.0); float d = min( min(dot(pq0, pq0), dot(pq1, pq1)), min(dot(pq2, pq2), dot(pq3, pq3)) ); float s = sign(max( max(cross2(v0, e0), cross2(v1, e1)), max(cross2(v2, e2), cross2(v3, e3)) )); // We can probably come up with a cheap sqrt approximation since we are only interested in d in [-0.5, 0.5]. return sqrt(d) * s; } ``` That would require passing 8 float varyings instead of 4 (not too bad), but also requires a lot more alu than the current implementation.
Bug 1759526 Comment 2 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
I played around with shadertoy, adapting https://www.shadertoy.com/view/XsXSz4# to work with a quad to get the signed distance of an arbitrary quad in screen space. ```C float cross2(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } float quad_distance(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { // Vectors along each edge. vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p3 - p2; vec2 e3 = p0 - p3; // Vectors from the point to each vertex. vec2 v0 = p - p0; vec2 v1 = p - p1; vec2 v2 = p - p2; vec2 v3 = p - p3; vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); vec2 pq3 = v3 - e3 * clamp(dot(v3, e3) / dot(e3, e3), 0.0, 1.0); float d = min( min(dot(pq0, pq0), dot(pq1, pq1)), min(dot(pq2, pq2), dot(pq3, pq3)) ); // The in-out test relies on consistent winding order of the vertices. // Probably wrong with transforms that, say, invert an axis. float s = sign(max( max(cross2(v0, e0), cross2(v1, e1)), max(cross2(v2, e2), cross2(v3, e3)) )); // We can probably come up with a cheap sqrt approximation since we are only interested in d in [-0.5, 0.5]. return sqrt(d) * s; } ``` That would require passing 8 float varyings instead of 4 (not too bad), but also requires a lot more alu than the current implementation.
I played around with shadertoy, adapting https://www.shadertoy.com/view/XsXSz4# to work with a quad to get the signed distance of an arbitrary quad in screen space. ```C float cross2(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } float quad_distance(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { // Vectors along each edge. vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p3 - p2; vec2 e3 = p0 - p3; // Vectors from the point to each vertex. vec2 v0 = p - p0; vec2 v1 = p - p1; vec2 v2 = p - p2; vec2 v3 = p - p3; vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); vec2 pq3 = v3 - e3 * clamp(dot(v3, e3) / dot(e3, e3), 0.0, 1.0); float d = min( min(dot(pq0, pq0), dot(pq1, pq1)), min(dot(pq2, pq2), dot(pq3, pq3)) ); // This in/out test relies on consistent winding order of the vertices. // Probably wrong with transforms like scale(-1, 1). float s = sign(max( max(cross2(v0, e0), cross2(v1, e1)), max(cross2(v2, e2), cross2(v3, e3)) )); // This one handles both windings: //float s = sign( // max( // max(cross2(v0, e0), cross2(v1, e1)), // max(cross2(v2, e2), cross2(v3, e3)) // ) * max( // max(-cross2(v0, e0), -cross2(v1, e1)), // max(-cross2(v2, e2), -cross2(v3, e3)) // ) //); // We can probably come up with a cheap sqrt approximation since we are only interested in d in [-0.5, 0.5]. return sqrt(d) * s; } ``` That would require passing 8 float varyings instead of 4 (not too bad), but also requires a lot more alu than the current implementation.
I played around with shadertoy, adapting https://www.shadertoy.com/view/XsXSz4# to work with a quad to get the signed distance of an arbitrary quad in screen space. ```C float cross2(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } float quad_distance(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { // Vectors along each edge. vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p3 - p2; vec2 e3 = p0 - p3; // Vectors from the point to each vertex. vec2 v0 = p - p0; vec2 v1 = p - p1; vec2 v2 = p - p2; vec2 v3 = p - p3; vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); vec2 pq3 = v3 - e3 * clamp(dot(v3, e3) / dot(e3, e3), 0.0, 1.0); float d = min( min(dot(pq0, pq0), dot(pq1, pq1)), min(dot(pq2, pq2), dot(pq3, pq3)) ); float c0 = cross2(v0, e0); float c1 = cross2(v1, e1); float c2 = cross2(v2, e2); float c3 = cross2(v3, e3); // We could simplify the in/out test below with this if we could ensure // consistent vertex winding, but we probably can't with transforms // like scale(-1, 1). //float s = sign(max(max(c0, c1), max(c2, c3))); float s = sign( max(max(c0, c1), max(c2, c3)) * max(max(-c0, -c1), max(-c2, -c3)) ); // We can probably come up with a cheap sqrt approximation since we are only interested in d in [-0.5, 0.5]. return sqrt(d) * s; } ``` That would require passing 8 float varyings instead of 4 (not too bad), but also requires a lot more alu than the current implementation.
I played around with shadertoy, adapting https://www.shadertoy.com/view/XsXSz4# to work with a quad to get the signed distance of an arbitrary quad in screen space. ```C float cross2(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } float quad_distance(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { // Vectors along each edge. vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p3 - p2; vec2 e3 = p0 - p3; // Vectors from the point to each vertex. vec2 v0 = p - p0; vec2 v1 = p - p1; vec2 v2 = p - p2; vec2 v3 = p - p3; vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); vec2 pq3 = v3 - e3 * clamp(dot(v3, e3) / dot(e3, e3), 0.0, 1.0); float d = min( min(dot(pq0, pq0), dot(pq1, pq1)), min(dot(pq2, pq2), dot(pq3, pq3)) ); float c0 = cross2(v0, e0); float c1 = cross2(v1, e1); float c2 = cross2(v2, e2); float c3 = cross2(v3, e3); // We could simplify the in/out test below with this if we could ensure // consistent vertex winding, but we probably can't with transforms // like scale(-1, 1). //float s = sign(max(max(c0, c1), max(c2, c3))); float s = sign( max(max(c0, c1), max(c2, c3)) * max(max(-c0, -c1), max(-c2, -c3)) ); // We can probably use a cheap sqrt approximation since we are only interested in d in [-0.5, 0.5]. // The following one looks fine. // return d * 2.0 * s return sqrt(d) * s; } ``` That would require passing 8 float varyings instead of 4 (not too bad), but also requires a lot more alu than the current implementation.
I played around with shadertoy, adapting https://www.shadertoy.com/view/XsXSz4# to get the signed distance of an arbitrary quad in screen space. ```C float cross2(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } float quad_distance(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { // Vectors along each edge. vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p3 - p2; vec2 e3 = p0 - p3; // Vectors from the point to each vertex. vec2 v0 = p - p0; vec2 v1 = p - p1; vec2 v2 = p - p2; vec2 v3 = p - p3; vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); vec2 pq3 = v3 - e3 * clamp(dot(v3, e3) / dot(e3, e3), 0.0, 1.0); float d = min( min(dot(pq0, pq0), dot(pq1, pq1)), min(dot(pq2, pq2), dot(pq3, pq3)) ); float c0 = cross2(v0, e0); float c1 = cross2(v1, e1); float c2 = cross2(v2, e2); float c3 = cross2(v3, e3); // We could simplify the in/out test below with this if we could ensure // consistent vertex winding, but we probably can't with transforms // like scale(-1, 1). //float s = sign(max(max(c0, c1), max(c2, c3))); float s = sign( max(max(c0, c1), max(c2, c3)) * max(max(-c0, -c1), max(-c2, -c3)) ); // We can probably use a cheap sqrt approximation since we are only interested in // the distance in the range [-0.5, 0. The following one is probably good enough: // return d * 2.0 * s return sqrt(d) * s; } ``` That would require passing 8 float varyings instead of 4 (not too bad), but also requires a lot more alu than the current implementation.
I played around with shadertoy, adapting https://www.shadertoy.com/view/XsXSz4# to get the signed distance of an arbitrary quad in screen space. ```C float cross2(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } float quad_distance(vec2 p, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { // Vectors along each edge. vec2 e0 = p1 - p0; vec2 e1 = p2 - p1; vec2 e2 = p3 - p2; vec2 e3 = p0 - p3; // Vectors from the point to each vertex. vec2 v0 = p - p0; vec2 v1 = p - p1; vec2 v2 = p - p2; vec2 v3 = p - p3; vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0); vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0); vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0); vec2 pq3 = v3 - e3 * clamp(dot(v3, e3) / dot(e3, e3), 0.0, 1.0); float d = min( min(dot(pq0, pq0), dot(pq1, pq1)), min(dot(pq2, pq2), dot(pq3, pq3)) ); float c0 = cross2(v0, e0); float c1 = cross2(v1, e1); float c2 = cross2(v2, e2); float c3 = cross2(v3, e3); // We could simplify the in/out test below with this if we could ensure // consistent vertex winding, but we probably can't with transforms // like scale(-1, 1). //float s = sign(max(max(c0, c1), max(c2, c3))); float s = sign( max(max(c0, c1), max(c2, c3)) * max(max(-c0, -c1), max(-c2, -c3)) ); // We can probably use a cheap sqrt approximation since we are only interested in // the distance in the range [-0.5, 0.5]. The following one is probably good enough: // return d * 2.0 * s return sqrt(d) * s; } ``` That would require passing 8 float varyings instead of 4 (not too bad), but also requires a lot more alu than the current implementation.