My task is to render quadratic Bezier curve (path) via Stage3d (Adobe Flash) technology, which have no any extensions for that drawing out-of-the box (while OpenGl have it, as I know). Yea, there is a Starling-Extension-Graphics, but it uses simple method to divide a curve segment to many straight lines, that generates very many triangles for my long curve path.
So.. There is a perfect way for rendering resolution independed shapes for Loop and Blinn. I've read GPUGems3 article (gpugems3_ch25.html)
and ported that fragment shader to AGAL2:
Quadratic Curve Pixel Shader
float4 QuadraticPS(float2 p : TEXCOORD0,
float4 color : COLOR0) : COLOR
{
// Gradients
float2 px = ddx(p);
float2 py = ddy(p);
// Chain rule
float fx = (2*p.x)*px.x - px.y;
float fy = (2*p.x)*py.x - py.y;
// Signed distance
float sd = (p.x*p.x - p.y)/sqrt(fx*fx + fy*fy);
// Linear alpha
float alpha = thickness - abs(sd);
if (alpha > 1) // Inside
color.a = 1;
else if (alpha < 0) // Outside
clip(-1);
else
// Near boundary
color.a = alpha;
return color;
}
It works. But there are two fundamental problems:
I don't understand that algorithm :(. I read about signed distance field, derivates and other... I thought a lot of hours and read again - but no result! My question is: Does anyone help me and explain what happens in that shader (line by line (!), if it possible)?
The second problem is that the curve is clipped at the corner of triangle and has a variable thickness. Please look at the picture:
https://monosnap.com/file/84EBOuQ1czNM5lprQ5VlnRUKP2mKmW
So if I draw a path it looks like this: https://monosnap.com/file/54Zs5Xui6s3BL6lNdZRCx9ibcV2bCF
I like that method by using one triangle per curve segment, because no any geometry needed. And I don't need to have very thick curves (1-2 px is excellent), but a variable thickness is a problem. Can anybody help me?
(Sorry for my English. It is not my native language.)
[edit1 by Spektre] just moved from comment and invalid answer
I plan to use one triangle per one curve segment, something like on the picture
the path consists from many triangles
one per one path segment (quadratic curve)
How to handle issue with this approach if all control points are collinear (lie on the same straight) or nearly collinear?
For 3 control point Bezier curves I would:
use triangles as primitives
enlarge control points to include area around curve to avoid artifacts
This way is fast and there is no problem to compute A',B',C' from A,B,C and vice versa. If the scale is constant (for example scale=1.25) then the max usable curve thickness<=2.0*min(|control_point-M|)*(scale-1.0).
For safer enlargement you can compute exact scale needed (for example in geometry shader) and pass it to vertex and fragment ... All of above can be done by Geometry shader. You should use transparency to correctly join the curves together. The average middle point should stay the same M=A+B+C=A'+B'+C'
if transparency is not an option
Then you need to change the approach so pass control points and position inside textures.
create one 2D float texture with control points
something like float pnt[9][N]
pnt[0,1,2][] is control point A(x,y,z)
pnt[3,4,5][] is control point B(x,y,z)
pnt[6,7,8][] is control point C(x,y,z)
also create 1D color texture
something like rgba col[N]
The x axis resolution of both textures = N is the number of Bezier curves
now draw single Quad covering entire screen
And inside fragment shader check if pixel is inside any of the curve. If yes output its color ...
This can get very slow for high Bezier curve count N
[edit1] almost collinear control points
for those I would use Quads
D,E are mirrored points A,B around C
D=C+C-A
E=C+C-B
C is the middle point M = (A+B+D+E)/4 = C = (A'+B'+C'+D')/4
and A',B',C',D' are enlarged A,B,D,E control points
A'=C+(A -C)*scale
B'=C+(B -C)*scale
A =C+(A'-C)/scale
B =C+(B'-C)/scale
This can be used for any Bezier not just almost colinear but it uses larger polygons so it will be slower on performance (more fragments then really needed)
Here more advanced/optimized GLSL approach with complete implementation of cubic BEZIER curves:
rendering 2D cubic BEZIER with GLSL
Related
I have a rather vague understanding of how rasterization is supposed to work.
So I totally understand how vertices make up a 3d image. I also ventured into model to world projection and even though I don't understand the math behind it ( I use helper libraries to multiply the matrices and have a chart denoting how to apply different transformations: rotate, scale, translate, etc).
So it's very easy for me to build some 3d model using blender and apply that logic to build a world matrix for each object.
But i've hit a brick wall trying to envision how to camera matrix is supposed to "look at" a specific cluster of vertices and what exactly happens to the object's world coordinates after the camera matrix is applied to the world matrix? and what does a camera matrix look like and how does the camera's "view axis" affect it's matrix (the camera could be looking at the z,x, y axis respectively)
I've managed to render a couple 3d objects with various rendering engines (openGL, XNA, etc) but most of it was due to having followed some guide on the internet or trying to interpret what some guy on youtube is trying to teach, and i'm still struggling trying to get an "intuitive" sense on how matrices are supposed to work as per camera parameters and how the camera is supposed to alter the object's world matrix
There are 5 steps in going from "world space" (Wx,Wy,Wz) to "screen space" (Sx,Sy): View, Clipping, Projection, Perspective Divide, Viewport. This is described pretty well here but some details are glossed over. I will try to explain the steps conceptually.
Imagine you have some vertices (what we want to render), a camera (with a position and orientation - which direction it is pointing), and a screen (a rectangular grid of WIDTHxHEIGHT pixels).
The Model Matrix I think you already understand: it scales, rotates, and translates each vertex into world coordinates (Wx,Wy,Wz,1.0). The last "1.0" (sometimes called the w component) allows us to represent translation and projection (as well as scaling and rotation) as a single 4x4 matrix.
The View Matrix (aka camera matrix) moves all the vertices to the point of view of the camera. I think of it as working in 2 steps: First it translates the entire scene (all vertices including the camera) such that in the new coordinate system the camera is at the origin. Second it rotates the entire scene such that the camera is looking from the origin in the direction of the -Z axis. There is a good description of this here. (Mathematically the rotation happens first, but I find it easier to visualize if I do the translation first.) At this point each vertex is in View coordinates (Vx,Vy,Vz,1.0). A good way to visualize this is to imagine the entire scene is embedded in ice; grab the block of ice and move it so the camera is at the origin pointing along the -z axis (and all the other objects in the world move along with the ice they are embedded in).
Next, the projection matrix encodes what kind of lens (wide angle vs telephoto) the camera has; in other words how much of the world will be visible on the screen. This is described well here but here is how it is calculated:
[ near/width ][ 0 ][ 0 ][ 0 ]
[ 0 ][ near/height ][ 0 ][ 0 ]
[ 0 ][ 0 ][(far+near)/(far-near) ][ 1 ]
[ 0 ][ 0 ][-(2*near*far)/(far-near)][ 0 ]
near = near plane distance (everything closer to the camera than this is clipped).
far = far plane distance (everything farther from the camera than this is clipped).
width = the widest object we can see if it is at the near plane.
height = the tallest object we can see if it is at the near plane.
. It results in "clip coordinates" (Cx,Cy,Cz,Cw=Vz). Note that the viewspace z coordinate (Vz) ends up in the w coordinate of the clip coordinates (Cw) (more on this below). This matrix stretches the world so that the camera's field of view is now 45 degrees up,down,left, and right. In other words, in this coordinate system if you look from the origin (camera position) straight along the -z axis (direction the camera is pointing) you will see what is in the center of the screen, and if you rotate your head up {down,left,right} you will see what will be at the top {bottom,left,right} of the screen. You can visualize this as a pyramid shape where the camera is at the top of the pyramid and the camera is looking straight down inside the pyramid. (This shape is called a "frustum" once you clip the top and bottom of the pyramid off with the near and far plane - see next paragraph.) The Cz value calculation makes vertices at the near plane have Cz=-Cw and vertices at the far plane have Cz=Cw
Clipping takes place in clip coordinates (which is why they are called that). Clipping means you take some scissors and clip away anything that is outside that pyramid shape. You also clip everything that is too close to the camera (the "near plane") and everything that is too far away from the camera (the "far plane"). See here for details.
Next comes the perspective divide. Remember that Cw == Vz? This is the distance from the camera to the vertex along the z axiz (the direction the camera is pointing). We divide each component by this Cw value to get Normalized Projection Coordinates (NPC) (Nx=Cx/Cw, Ny=Cy/Cw, Nz=Cz/Cw, Nw=Cw/Cw=1.0). All these values (Nx, Ny and Nz) will be between -1 and 1 because we clipped away anything where Cx > Cw or Cx < -Cw or Cy > Cw or Cy < -Cw or Cz > Cw or Cz < -Cw. Again see here for lots of details on this. The perspective divide is what makes things that are farther away appear smaller. The farther away from the camera something is, the larger the Cw (Vz) is, and the more its X and Y coordinate will be reduced when we divide.
The final step is the viewport transform. Nx Ny and Nz (each ranging from -1 to 1) are converted to pixel coordinates. For example Nx=-1 is at the left of the screen and Nx=1 is at the right of the screen, so we get Sx = (Nx * WIDTH/2) + (WIDTH/2) or equivalently Sx = (Nx+1) * WIDTH. Similar for Sy. You can think of Sz as the value that will be used in a depth buffer, so it needs to range from 0 for vertices at the near plane (Vz=near) to the maximum value that the depth buffer can hold (e.g. 2^24= 16777216 for a 24 bit z buffer) for vertices at the far plane (Vz=far).
The "camera matrix" as you called it sounds like a combination of two matrices: the view matrix and the projection matrix. It's possible you're only talking about one of these, but it's not clear.
View matrix: The view matrix is the inverse of what the camera's model matrix would be if you drew it in the world. In order to draw different camera angles, we actually move the entire world in the opposite direction - so there is only one camera angle.
Usually in OpenGL, the camera "really" stays at (0,0,0) and looks along the Z axis in the positive direction (towards 0,0,+∞). You can apply a rotation to the projection matrix to get a different direction, but why would you? Do all the rotation in the view matrix and your life is simpler.
So if you want your camera to be at (0,3,0) for example, instead of moving the camera up 3 units, we leave it at (0,0,0) and move the entire world down 3 units. If you want it to rotate 90 degrees, we actually rotate the world 90 degrees in the opposite direction. The world doesn't mind - it's just numbers in a computer - it doesn't get dizzy.
We only do this when rendering. All of the game physics calculations, for example, aren't done in the rotated world. The coordinates of the stuff in the world don't get changed when we rotate the camera - except inside the rendering system. Usually, we tell the GPU the normal world coordinates of the objects, and we get the GPU to move and rotate them for us, using a matrix.
Projection matrix: You know the view frustum? This shape you've probably seen before: (credit)
Everything inside the cut-off pyramid shape (frustum) is displayed on the screen. You know this.
Except the computer doesn't actually render in a frustum. It renders a cube. The view matrix transforms the frustum into a cube.
If you're familiar with linear algebra, you may notice that a 3D matrix can't make a cube into a frustum. That's what the 4th coordinate (w) is for. After this calculation, the x, y and z coordinates are all divided by w. By using a view matrix that makes w depend on z, the coordinates of far-away points get divided by a larger number, so they get pushed towards the middle of the screen - that's how a cube is able to turn into a frustum.
You don't have to have a frustum - that's what you get with a perspective projection. You can also use an orthographic projection, which turns a cube into a cube, by not changing w.
Unless you want to do a bunch of math yourself, I'd recommend you just use the library functions to generate projection matrices.
If you're multiplying vertices by several matrices in a row it's more efficient to combine them into one matrix, and then multiply the vertices by the combined matrix - hence you will often see MVP, MV and VP matrices used. (M = model matrix - I think it's the same thing you called a world matrix)
I am writing a function to draw an approximate circle on a square array (in Matlab, but the problem is mainly algorithmic).
The goal is to produce a mask for integrating light that falls on a portion of a CCD sensor from a diffraction-limited point source (whose diameter corresponds to a few pixels on the CCD array). In summary, the CCD sensor sees a pattern with revolution-symmetry, that has of course no obligation to be centered on one particular pixel of the CCD (see example image below).
Here is the algorithm that I currently use to produce my discretized circular mask, and which works partially (Matlab/Octave code):
xt = linspace(-xmax, xmax, npixels_cam); % in physical coordinates (meters)
[X Y] = meshgrid(xt-center(1), xt-center(2)); % shifted coordinate matrices
[Theta R] = cart2pol(X,Y);
R = R'; % cart2pol uses a different convention for lines/columns
mask = (R<=radius);
As you can see, my algorithm selects (sets to 1) all the pixels whose physical distance (in meters) is smaller or equal to a radius, which doesn't need to be an integer.
I feel like my algorithm may not be the best solution to this problem. In particular, I would like it to include the pixel in which the center is present, even when the radius is very small.
Any ideas ?
(See http://i.stack.imgur.com/3mZ5X.png for an example image of a diffraction-limited spot on a CCD camera).
if you like to select pixels if and only if they contain any part of the circle C:
in each pixel place a small circle A with the radius = halv size of the pixel, and another one around it with R=sqrt(2)*half size of the circle (a circumscribed circle)
To test if two circles touch each other you just calculate the center to center distances and subtract the sum of the two radii.
If the test circle C is within A then you select the pixel. If it's within B but not C you need to test all four pixel sides for overlap like this Circle line-segment collision detection algorithm?
A brute force approximate method is to make a much finer grid within each pixel and test each center point in that grid.
This is a well-studied problem. Several levels of optimization are possible:
You can brute-force check if every pixel is inside the circle. (r^2 >= (x-x0)^2 + (y-y0)^2)
You can brute-force check if every pixel in a square bounding the circle is inside the circle. (r^2 >= (x-x0)^2 + (y-y0)^2 where |x-x0| < r and |y-y0| < r)
You can go line-by-line (where |y-y0| < r) and calculate the starting x ending x and fill all the lines in between. (Although square roots aren't cheap.)
There's an infinite possibility of more sophisticated algorithms. Here's a common one: http://en.wikipedia.org/wiki/Midpoint_circle_algorithm (filling in the circle is left as an exercise)
It really depends on how sophisticated you want to be based on how imperative good performance is.
I have a stack of images (about 180 of them) and there are 2 stars (just basic annotations) on every single image. Hence, the position (x,y) of the two stars are provided initially. The dimensions of all these images are fixed and constant.
The 'distance' between the image is about 1o with the origin to be the center (width/2, height/2) of every single 2D image. Note that, if this is plotted out and interpolated nicely, the stars would actually form a ring of an irregular shape.
The dotted red circle and dotted purple circle are there to give a stronger scent of a 3D space and the arrangement of the 2D images (like a fan). It also indicates that each slice is about 1o apart.
With the provided (x,y) that appeared in the 2D image, how do you get the corresponding (x,y,z) in the 3d space knowing that each image is about 1o apart?
I know that MATLAB had 3D plotting capabilities, how should I go about implementing the solution to the above scenario? (Unfortunately, I have very little experience plotting 3D with MATLAB)
SOLUTION
Based on the accepted answer, I looked up a bit further: spherical coordinate system. Based on the computation of phi, rho and theta, I could reconstruct the ring without problems. Hopefully this helps anyone with similar problems.
I have also documented the solution here. I hope it helps someone out there, too:
http://gray-suit.blogspot.com/2011/07/spherical-coordinate-system.html
I believe the y coordinate stays as is for 3D, so we can treat this as converting 2D x and image angle to an x and z when viewed top down.
The 2D x coordinate is the distance from the origin in 3D space (viewed top down). The image angle is the angle the point makes with respect to the x axis in 3D space (viewed top down). So the x coordinate (distance from orign) and the image angle (angle viewed top down) makes up the x and z coordinates in 3D space (or x and y if viewed top down).
That is a polar coordinate.
Read how to convert from polar to cartesian coordinates to get your 3D x and z coordinates.
I'm not great at maths either, here's my go:
3D coords = (2Dx * cos(imageangle), 2Dy, 2Dx * sin(imageangle))
Given the 2D coordinates (x,y) just add the angle A as a third coordinate: (x,y,A). Then you have 3D.
If you want to have the Anotations move on a circle of radius r in 3D you can just calculate:
you can use (r*cos(phi),r*sin(phi),0) which draws a circle in the XY-plane and rotate it with a 3x3 rotation matrix into the orientation you need.
It is not clear from you question around which axis your rotation is taking place. However, my answer holds for a general rotation axis.
First, put your points in a 3D space, lying on the X-Y plane. This means the points have a 0 z-coordinate. Then, apply a 3D rotation of the desired angle around the desired axis - in your example, it is a one degree rotation. You could calculate the transformation matrix yourself (should not be too hard, google "3D rotation matrix" or similar keywords). However, MATLAB makes it easier, using the viewmtx function, which gives you a 4x4 rotational matrix. The extra (fourth) dimension is dependent on the projection you specify (it acts like a scaling coefficient), but in order to make things simple, I will let MATLAB use its default projection - you can read about it in MATLAB documentation.
So, to make the plot clearer, I assume four points which are the vertices of a square lying on the x-y plane (A(1,1), B(1,-1), C(-1,-1), D(1,-1)).
az = 0; % Angle (degrees) of rotation around the z axis, measured from -y axis.
el = 90; % Angle (degrees) of rotation around the y' axis (the ' indicates axes after the first rotation).
x = [1,-1, -1, 1,1]; y = [1, 1, -1, -1,1]; z = [0,0, 0, 0,0]; % A square lying on the X-Y plane.
[m,n] = size(x);
x4d = [x(:),y(:),z(:),ones(m*n,1)]'; % The 4D version of the points.
figure
for el = 90 : -1 :0 % Start from 90 for viewing directly above the X-Y plane.
T = viewmtx(az, el);
x2d = T * x4d; % Rotated version of points.
plot3 (x2d(1,:), x2d(2,:),x2d(3,:),'-*'); % Plot the rotated points in 3D space.
grid
xlim ([-2,2]);
ylim ([-2,2]);
zlim([-2,2]);
pause(0.1)
end
If you can describe your observation of a real physical system (like a binary star system) with a model, you can use particle filters.
Those filters were developed to locate a ship on the sea, when only one observation direction was available. One tracks the ship and estimates where it is and how fast it moves, the longer one follows, the better the estimates become.
This may be a little hard to describe since I don't have a sample. I'm trying to find a math function or full 3d function in php or a similar language that can help me with the following effect:
imagine if you were to take a flat sheet or paper and glue it on a glass of water. It wouldn't be flat any more. It would have a curve, and one of its sides might end up being slightly hidden.
Anyone can refer me to a good library or resource on the web where such functions can be found?
Lets say the center of your paper is x=0, and your cylinder is vertical along the y-axis. Your x-coordinate on the paper could be equated to an arc length on the surface of the cylinder. Arc length (s) is equal to the angle (in radians) times the radius. Your radius is given, so you can compute the angle from the arc length and radius. Angle = Arc Length / Radius. Since you now have the angle and the radius, you can compute the new x-offset, which would be (radius * cos(angle)). So your mapping functions would be:
new_x = radius * cos(old_x/radius)
new_y = old_y; //y-coordinate doesn't change
new_z = radius * sin(old_x/radius);
You'll have to enforce boundaries (keep x on the paper, and make sure it's not more than half the circumference (x must be less than or equal to PI*r). Also, watch the signs... especially the z-coordinate, which will depend on whether your coordinate system is right-handed or left-handed, or where you imagine the paper starting on the cylindar (back or front). Finally, you can use standard matrix transforms to move and position the paper/cylinder in 3D space once you have the warped coordinates.
Where can I find algorithms for image distortions? There are so much info of Blur and other classic algorithms but so little of more complex ones. In particular, I am interested in swirl effect image distortion algorithm.
I can't find any references, but I can give a basic idea of how distortion effects work.
The key to the distortion is a function which takes two coordinates (x,y) in the distorted image, and transforms them to coordinates (u,v) in the original image. This specifies the inverse function of the distortion, since it takes the distorted image back to the original image
To generate the distorted image, one loops over x and y, calculates the point (u,v) from (x,y) using the inverse distortion function, and sets the colour components at (x,y) to be the same as those at (u,v) in the original image. One ususally uses interpolation (e.g. http://en.wikipedia.org/wiki/Bilinear_interpolation ) to determine the colour at (u,v), since (u,v) usually does not lie exactly on the centre of a pixel, but rather at some fractional point between pixels.
A swirl is essentially a rotation, where the angle of rotation is dependent on the distance from the centre of the image. An example would be:
a = amount of rotation
b = size of effect
angle = a*exp(-(x*x+y*y)/(b*b))
u = cos(angle)*x + sin(angle)*y
v = -sin(angle)*x + cos(angle)*y
Here, I assume for simplicity that the centre of the swirl is at (0,0). The swirl can be put anywhere by subtracting the swirl position coordinates from x and y before the distortion function, and adding them to u and v after it.
There are various swirl effects around: some (like the above) swirl only a localised area, and have the amount of swirl decreasing towards the edge of the image. Others increase the swirling towards the edge of the image. This sort of thing can be done by playing about with the angle= line, e.g.
angle = a*(x*x+y*y)
There is a Java implementation of lot of image filters/effects at Jerry's Java Image Filters. Maybe you can take inspiration from there.
The swirl and others like it are a matrix transformation on the pixel locations. You make a new image and get the color from a position on the image that you get from multiplying the current position by a matrix.
The matrix is dependent on the current position.
here is a good CodeProject showing how to do it
http://www.codeproject.com/KB/GDI-plus/displacementfilters.aspx
there has a new graphic library have many feature
http://code.google.com/p/picasso-graphic/
Take a look at ImageMagick. It's a image conversion and editing toolkit and has interfaces for all popular languages.
The -displace operator can create swirls with the correct displacement map.
If you are for some reason not satisfied with the ImageMagick interface, you can always take a look at the source code of the filters and go from there.