Radial gradient equation - graphics

Given:
A point P, circle 1 and circle 2's positions and radii
What is:
The equation for T, the 'mix level' between color 1 and 2 (a value between 0 to 1)
Many radial gradient equations only apply to concentric circles or circles that share a position. I'm looking for something that matches the image below, created using Quartz (Core Graphics). I am writing a GLSL shader, but I need to understand the math first.

If this is in 2D, then you can write the parameters of the circle that your point lies on as:
x3=T*x1+(1-T)*x2
y3=T*y1+(1-T)*y2
r3=T*r1+(1-T)*r2
EDIT: Of course, that circle can be represented as:
(x3-xP)^2+(y3-yP)^2=r3^2
You can substitute the first 3 equations into the last (and remember that (xP, yP) is your point) to get 1 equation with only T as a variable that is quadratic in T, so it is easy to solve for T. Doing so gives us:
T=(-r2*(r1-r2)+(x1-x2)*(x2-xP)+(y1-y2)(y2-yP)
{+-}sqrt(r2^2*((x1-xP)^2+(y1-yP)^2)-2*r1*r2*((x1-xP)*(x2-xP)
+(y1-yP)*(y2-yP))+r1^2*((x2-xP)^2+(y2-yP)^2)
-(x2*y1-xP*y1-x1*y2+xP*y2+x1*yP-x2*yP)^2))
/((r1-r2)^2-(x1-x2)^2-(y1-y2)^2)
I know that that is a bit hard to read, but it is not actually that bad mathematically. It is just addition, multiplication, and squaring (which is really just multiplication).

Related

What's the different between using modelViewmatrix directly and using normalMatrix instead? [duplicate]

I am working on some shaders, and I need to transform normals.
I read in few tutorials the way you transform normals is you multiply them with the transpose of the inverse of the modelview matrix. But I can't find explanation of why is that so, and what is the logic behind that?
It flows from the definition of a normal.
Suppose you have the normal, N, and a vector, V, a tangent vector at the same position on the object as the normal. Then by definition N·V = 0.
Tangent vectors run in the same direction as the surface of an object. So if your surface is planar then the tangent is the difference between two identifiable points on the object. So if V = Q - R where Q and R are points on the surface then if you transform the object by B:
V' = BQ - BR
= B(Q - R)
= BV
The same logic applies for non-planar surfaces by considering limits.
In this case suppose you intend to transform the model by the matrix B. So B will be applied to the geometry. Then to figure out what to do to the normals you need to solve for the matrix, A so that:
(AN)·(BV) = 0
Turning that into a row versus column thing to eliminate the explicit dot product:
[tranpose(AN)](BV) = 0
Pull the transpose outside, eliminate the brackets:
transpose(N)*transpose(A)*B*V = 0
So that's "the transpose of the normal" [product with] "the transpose of the known transformation matrix" [product with] "the transformation we're solving for" [product with] "the vector on the surface of the model" = 0
But we started by stating that transpose(N)*V = 0, since that's the same as saying that N·V = 0. So to satisfy our constraints we need the middle part of the expression — transpose(A)*B — to go away.
Hence we can conclude that:
transpose(A)*B = identity
=> transpose(A) = identity*inverse(B)
=> transpose(A) = inverse(B)
=> A = transpose(inverse(B))
My favorite proof is below where N is the normal and V is a tangent vector. Since they are perpendicular their dot product is zero. M is any 3x3 invertible transformation (M-1 * M = I). N' and V' are the vectors transformed by M.
To get some intuition, consider the shear transformation below.
Note that this does not apply to tangent vectors.
Take a look at this tutorial:
https://paroj.github.io/gltut/Illumination/Tut09%20Normal%20Transformation.html
You can imagine that when the surface of a sphere stretches (so the sphere is scaled along one axis or something similar) the normals of that surface will all 'bend' towards each other. It turns out you need to invert the scale applied to the normals to achieve this. This is the same as transforming with the Inverse Transpose Matrix. The link above shows how to derive the inverse transpose matrix from this.
Also note that when the scale is uniform, you can simply pass the original matrix as normal matrix. Imagine the same sphere being scaled uniformly along all axes, the surface will not stretch or bend, nor will the normals.
If the model matrix is made of translation, rotation and scale, you don't need to do inverse transpose to calculate normal matrix. Simply divide the normal by squared scale and multiply by model matrix and we are done. You can extend that to any matrix with perpendicular axes, just calculate squared scale for each axes of the matrix you are using instead.
I wrote the details in my blog: https://lxjk.github.io/2017/10/01/Stop-Using-Normal-Matrix.html
Don't understand why you just don't zero out the 4th element of the direction vector before multiplying with the model matrix. No inverse or transpose needed. Think of the direction vector as the difference between two points. Move the two points with the rest of the model - they are still in the same relative position to the model. Take the difference between the two points to get the new direction, and the 4th element, cancels out to zero. Lot cheaper.

how to calculate anti/clockwise angle in direction of lines?

I need to offset a curve, which by the simplest way is just shifting the points perpendicularly. I can access each point to calculate angle of each line along given path, for now I use atan2. Then I take those two angle and make average of it. It returns the shortest angle, not what I need in this case.
How can I calculate angle of each connection? Concerning that I am not interested in the shortest angle but the one that would create parallel offset curve.
Assuming 2D case...
So do a cross product of direction vectors of 2 neighboring lines the sign of z coordinate of the result will tell you if the lines are CW/CCW
So if you got 3 consequent control points on the polyline: p0,p1,p2 then:
d1 = p1-p0
d2 = p2-p1
if you use some 3D vector math then convert them to 3D by setting:
d1.z=0;
d2.z=0;
now compute 3D cross:
n = cross(d1,d2)
which returns vector perpendicular to both vectors of size equals to the area of quad (parallelogram) constructed with d1,d2 as base vectors. The direction (from the 2 possible) is determined by the winding rule of the p0,p1,p2 so inspecting z of the result is enough.
The n.x,n.y are not needed so you can compute directly without doing full cross product:
n.z=(d1.x*d2.y)-(d1.y*d2.x)
if (n.z>0) case1
if (n.z<0) case2
if the case1 is CW or CCW depends on your coordinate system properties (left/right handness). This approach is very commonly used in CG fur back face culling of polygons ...
if n.z is zero it means that your vectors/lines are either parallel or at lest one of them is zero.
I think these might interest you:
draw outline for some connected lines
How can I create an internal spiral for a polygon?
Also in 2D you do not need atan2 to get perpendicular vector... You can do instead this:
u = (x,y)
v = (-y,x)
w = (x,-y)
so u is any 2D vector and v,w are the 2 possible perpendicular vectors to u in 2D. they are the result of:
cross((x,y,0),(0,0,1))
cross((0,0,1),(x,y,0))

How to calculate correct plane-frustum intersection?

Question:
I need to calculate intersection shape (purple) of plane defined by Ax + By + Cz + D = 0 and frustum defined by 4 rays emitting from corners of rectangle (red arrows). The result shoud be quadrilateral (4 points) and important requirement is that result shape must be in plane's local space. Plane is created with transformation matrix T (planes' normal is vec3(0, 0, 1) in T's space).
Explanation:
This is perspective form of my rectangle projection to another space (transformation / matrix / node). I am able to calculate intersection shape of any rectangle without perspective rays (all rays are parallel) by plane-line intersection algorithm (pseudocode):
Definitions:
// Plane defined by normal (A, B, C) and D
struct Plane { vec3 n; float d; };
// Line defined by 2 points
struct Line { vec3 a, b; };
Intersection:
vec3 PlaneLineIntersection(Plane plane, Line line) {
vec3 ba = normalize(line.b, line.a);
float dotA = dot(plane.n, l.a);
float dotBA = dot(plane.n, ba);
float t = (plane.d - dotA) / dotBA;
return line.a + ba * t;
}
Perspective form comes with some problems, because some of rays could be parallel with plane (intersection point is in infinite) or final shape is self-intersecting. Its works in some cases, but it's not enough for arbitary transformation. How to get correct intersection part of plane wtih perspective?
Simply, I need to get visible part of arbitary plane by arbitary perspective "camera".
Thank you for suggestions.
Intersection between a plane (one Ax+By+Cx+D equation) and a line (two planes equations) is a matter of solving the 3x3 matrix for x,y,z.
Doing all calculations on T-space (origin is at the top of the pyramid) is easier as some A,B,C are 0.
What I don't know if you are aware of is that perspective is a kind of projection that distorts the z ("depth", far from the origin). So if the plane that contains the rectangle is not perpendicular to the axis of the fustrum (z-axis) then it's not a rectangle when projected into the plane, but a trapezoid.
Anyhow, using the projection perspective matrix you can get projected coordinates for the four rectangle corners.
To tell if a point is in one side of a plane or in the other just put the point coordinates in the plane equation and get the sign, as shown here
Your question seems inherently mathematic so excuse my mathematical solution on StackOverflow. If your four arrows emit from a single point and the formed side planes share a common angle, then you are looking for a solution to the frustum projection problem. Your requirements simplify the problem quite a bit because you define the plane with a normal, not two bounded vectors, thus if you agree to the definitions...
then I can provide you with the mathematical solution here (Internet Explorer .mht file, possibly requiring modern Windows OS). If you are thinking about an actual implementation then I can only direct you to a very similar frustum projection implementation that I have implemented/uploaded here (Lua): https://github.com/quiret/mta_lua_3d_math
The roadmap for the implementation could be as follows: creation of condition container classes for all sub-problems (0 < k1*a1 + k2, etc) plus the and/or chains, writing algorithms for the comparisions across and-chains as well as normal-form creation, optimization of object construction/memory allocation. Since each check for frustum intersection requires just a fixed amount of algebraic objects you can implement an efficient cache.

Perspective Projection: Proving that 1/z is Linear?

In 3D rendering (or geometry for that matter), in the rasterization algorithm, when you project the vertices of a triangle onto the screen and then find if a pixel overlaps the 2D triangle, you often need to find the depth or the z-coordinate of the triangle that the pixel overlaps. Generally, the method consists of computing the barycentric coordinates of the pixel in the 2D "projected" image of the triangle, and then use these coordinates to interpolate the triangle original vertices z-coordinates (before the vertices got projected).
Now it's written in all text books that you can't interpolate the vertices coordinates of the vertices directly but that you need to do this instead:
(sorry can't get Latex to work?)
1/z = w0 * 1/v0.z + w1 * 1/v1.z + w2 * 1/v2.z
Where w0, w1, and w2 are the barycentric coordinates of the "pixel" on the triangle.
Now, what I am looking after, are two things:
what would be the formal proof to show that interpolating z doesn't work?
what would be the formal proof to show that 1/z does the right thing?
To show this is not home work ;-) and that I have made some work on my own, I have found the following explanation for question 2.
Basically a triangle can be defined by a plane equation. Thus you can write:
Ax + By + Cz = D.
Then you isolate z to get z = (D - Ax - By)/C
Then you divide this formula by z as you would with a perspective divide and if you develop, regroup, etc. you get:
1/z = C/D + A/Dx/z + B/Dy/z.
Then we name C'=C/D B'=B/D and A'=A/D you get:
1/z = A'x/z + B'y/z + C'
It says that x/z and y/z are just the coordinates of the points on the triangles once projected on the screen and that the equation on the right is an "affine" function therefore 1/z is a linear function???
That doesn't seem like a demonstration to me? Or maybe it's the right idea, but can't really say how you can tell by just looking at the equation that this is an affine function. If you multiply all the terms you just get:
A'x + B'y + C'z = 1.
Which is just basically our original equations (just need to replace A' B' and C' with the proper term).
Not sure what you are trying to ask here, but if you look at:
1/z = A'x/z + B'y/z + C'
and rewrite it as:
1/z = A'u + B'v + C'
where (u,v) are screen coordinates of the triangle after perspective projection, you can see that the depth (z) of a point on the triangle is not linearly related to (u,v) but 1/depth is and that is what the textbooks are trying to teach you.

Finding most distant point in circle from point

I'm trying to find the best way to get the most distant point of a circle from a specified point in 2D space. What I have found so far, is how to get the distance between the point and the circle position, but I'm not entirely sure how to expand this to find the most distant point of the circle.
The known variables are:
Point a
Point b (circle position)
Radius r (circle radius)
To find the distance between the point and the circle position, I have found this:
xd = x2 - x1
yd = y2 - y1
Distance = SquareRoot(xd * xd + yd * yd)
It seems to me, this is part of the solution. How would this be expanded to get the position of Point x in the below image?
As an additional but optional part of the question: I have read in some places that it would be possible to get the distance portion without using the Square Root, which is very performance intensive and should be avoided if fast code is necessary. In my case, I would be doing this calculation quite often; Any comments on this within the context of the main question would be welcome too.
What about this?
Calculate A-B.
We now have a vector pointing from the center of the circle towards A (if B is the origin, skip this and just consider point A a vector).
Normalize.
Now we have a well defined length (the length is 1)
If the circle is not of unit radius, multiply by radius. If it is unit radius, skip this.
Now we have the correct length.
Invert sign (can be done in one step with 3., just multiply with the negative radius)
Now our vector points in the correct direction.
Add B (if B is the origin, skip this).
Now our vector is offset correctly so its endpoint is the point we want.
(Alternatively, you could calculate B-A to save the negation, but then you have to do one more operation to offset the origin correctly.)
By the way, it works the same in 3D, except the circle would be a sphere, and the vectors would have 3 components (or 4, if you use homogenous coords, in this case remember -- for correctness -- setting w to 0 when "turning points into vectors" and to 1 at the end when making a point from the vector).
EDIT:
(in reply of pseudocode)
Assuming you have a vec2 class which is a struct of two float numbers with operators for vector subtraction and scalar multiplicaion (pretty trivial, around a dozen lines of code) and a function normalize which needs to be no more than a shorthand for multiplying with inv_sqrt(x*x+y*y), the pseudocode (my pseudocode here is something like a C++/GLSL mix) could look something like this:
vec2 most_distant_on_circle(vec2 const& B, float r, vec2 const& A)
{
vec2 P(A - B);
normalize(P);
return -r * P + B;
}
Most math libraries that you'd use should have all of these functions and types built-in. HLSL and GLSL have them as first type primitives and intrinsic functions. Some GPUs even have a dedicated normalize instruction.

Resources