y-direction shearing matrix and its equivalence - graphics

I want to know how rotation and scaling equivalent y-direction shearing matrix?
1 0 0
shx 1 -shy.xref
0 0 1
I understood what shearing mean but how can get it using rotation and scaling ??
thank you :)

Shearing cannot be constructed using just rotation and scaling.
Shearing is an affine transformation and rotation and scaling are "rigid" transformation which are less expressive.
more on this:
http://en.wikipedia.org/wiki/Affine_transformation

Yup it can be done, a rotation followed by non uniform scaling and reverse rotation. You can find the details here in third question http://www.cs.cmu.edu/~djames/15-462/Fall03/assts/15-462-Fall03-wrAssign1-answer.pdf. you can try the following openGL code as well. It rotates a rectangle by 45 degree then scales in x-axis. and then rotates in -26 degree i.e. atan(0.5). 0.5 comes from finding the angle between x-axis and one side after scaling in x-direction.
glRotatef(-26.0, 0.0, 0.0, 1.0);
glScalef(2,1,1);
glRotatef(45.0, 0.0, 0.0, 1.0);
glRectf(0, 0, 25.0, 25.0);

Related

How do I rotate a point on the surface of a sphere given 3 degrees of rotation?

I have a point on a sphere that needs to be rotated. I have 3 different degrees of rotation (roll, pitch, yaw). Are there any formulas I could use to calculate where the point would end up after applying each rotation? For simplicity sake, the sphere can be centered on the origin if that helps.
I've tried looking at different ways of rotation, but nothing quite matches what I am looking for. If I needed to just rotate the sphere, I could do that, but I need to know the position of a point based on the rotation of the sphere.
Using Unity for an example, this is outside of unity in a separate project so using their library is not possible:
If the original point is at (1, 0, 0)
And the sphere then gets rotated by [45, 30, 15]:
What is the new (x, y, z) of the point?
If you have a given rotation as a Quaternion q, then you can rotate your point (Vector3) p like this:
Vector3 pRotated = q * p;
And if you have your rotation in Euler Angles then you can always convert it to a Quaternion like this (where x, y and z are the rotations in degrees around those axes):
Quaternion q = Quaternion.Euler(x,y,z);
Note that Unity's euler angles are defined so that first the object is rotated around the z axis, then around the x axis and finally around the y axis - and that these axes are all the in the space of the parent transform, if any (not the object's local axes, which will move with each rotation).
So I suppose that the z-axis would be roll, the x-axis would be pitch and the y axis would be yaw.You might have to switch the signs on some axes to match the expected result - for example, a positive x rotation will tilt the object downwards (assuming that the object's notion of forward is in its positive z direction and that up is in its positive y direction).

understanding glm::perspective matrix

I'm trying to implement a simple 3d render. I have implemented a perspective projection matrix similar to glm::perspective. I have read that a perspective projection matrix transforms vertices such that after the perspective division, visible region, i.e., objects that lie inside the specified frustum fall in the range [-1,1], but when I tested some values with a matrix returned by glm::perspective results are not similar to my understanding.
float nearPlane = 0.1f;
float farPlane = 100.0f;
auto per =
glm::perspective(45.0f, (float)(window_width * 1.0 / window_height),
nearPlane, farPlane);
// z=nearplane
print(per * glm::vec4(1, -1, -0.1, 1));
// z=farplane
print(per * glm::vec4(1, -1, -100, 1));
// z between nearplane and farplane
print(per * glm::vec4(1, -1, -5, 1));
// z beyond far plane
print(per * glm::vec4(1, -1, -200, 1));
// z behind the camera
print(per * glm::vec4(1, -1, 0.1, 1));
// z between camera and near plane
print(per * glm::vec4(1, -1, -0.09, 1));
As per my understanding, if vertices have a z coordinate which lies towards positive z-direction from nearPlane then after perspective divide z/w value should be <-1 but as shown in the picture below it is not the case. what am I missing?
as per my understanding if vertices has z coordinate which is lies towards positive z direction from nearPlane then after perspective divide z/w value should be <-1 but as shown in picture below it is not the case. what am i missing?
That's simply not the case. There is a singularity at z=0 (camera plane), and the sign of the function flips (camera is looking to the left; blue vertical line is the near clipping plane):
Those values are still outside the [-1,1] range, telling us that they are outside the camera frustum and should be clipped accordingly.
You might be confused because you're thinking that "smaller z/w values mean that the point is closer to the camera". But that's true only in-front of the camera. In fact the depth buffer values matter only if the fragment isn't clipped -- i.e. in the [-1,1] range, where that relation happens to be correct.

Homogeneous coordinates and perspective-correctness?

Does the technique that vulkan uses (and I assume other graphics libraries too) to interpolate vertex attributes in a perspective-correct manner require that the vertex shader must normalize the homogenous camera-space vertex position (ie: divide through by the w-coordinate such that the w-coordinate is 1.0) prior to multiplication by a typical projection matrix of the form...
g/s 0 0 0
0 g 0 n
0 0 f/(f-n) -nf/(f-n)
0 0 1 0
...in order for perspective-correctness to work properly?
Or, will perspective-correctness continue to work on any homogeneous vertex position in camera-space (with a w-coordinate other than 1.0)?
(I didn't completely follow the perspective-correctness math, so it is unclear which to me which is the case.)
Update:
In order to clarify terminology:
vec4 modelCoordinates = vec4(x_in, y_in, z_in, 1);
mat4 modelToWorld = ...;
vec4 worldCoordinates = modelToWorld * modelCoordinates;
mat4 worldToCamera = ...;
vec4 cameraCoordinates = worldToCamera * worldCoordinates;
mat4 cameraToProjection = ...;
vec4 clipCoordinates = cameraToProjection * cameraCoordinates;
output(clipCoordinates);
cameraToProjection is a matrix like the one shown in the question
The question is does cameraCoordinates.w have to be 1.0?
And consequently the last row of both the modelToWorld and worldToCamera matricies have to be 0 0 0 1?
You have this exactly backwards. Doing the perspective divide in the shader is what prevents perspective-correct interpolation. The rasterizer needs the perspective information provided by the W component to do its job. With a W of 1, the interpolation is done in window space, without any regard to perspective.
Provide a clip-space coordinate to the output of your vertex processing stage, and let the system do what it exists to do.
the vertex shader must normalize the homogenous camera-space vertex position (ie: divide through by the w-coordinate such that the w-coordinate is 1.0) prior to multiplication by a typical projection matrix of the form...
If your camera-space vertex position does not have a W of 1.0, then one of two things has happened:
You are deliberately operating in a post-projection world space or some similar construct. This is a perfectly valid thing to do, and the math for a camera space can be perfectly reasonable.
Your code is broken somewhere. That is, you intend for your world and camera space to be a normal, Euclidean, non-homogeneous space, but somehow the math didn't work out. Obviously, this is not a perfectly valid thing to do.
In both cases, dividing by W is the wrong thing to do. If your world space that you're placing a camera into is post-projection (such as in this example), dividing by W will break your perspective-correct interpolation, as outlined above. If your code is broken, dividing by W will merely mask the actual problem; better to fix your code than to hide the bug, as it may crop up elsewhere.
To see whether or not the camera coordinates need to be in normal form, let's represent the camera coordinates as multiples of w, so they are (wx,wy,wz,w).
Multiplying through by the given projection matrix, we get the clip coordinates (wxg/s, wyg, fwz/(f-n)-nfw/(f-n)), wz)
Calculating the x-y framebuffer coordinates as per the fixed Vulkan formula we get (P_x * xg/sz +O_x, P_y * Hgy/z + O_y). Notice this does not depend on w, so the position in the framebuffer of a polygons verticies doesn't require the camera coordinates be in normal form.
Likewise calculation of the barycentric coordinates of fragments within a polygon only depends on x,y in framebuffer coordinates, and so is also independant of w.
However perspective-correct perspective interpolation of fragment attributes does depend on W_clip of the verticies as this is used in the formula given in the Vulkan spec. As shown above W_clip is wz which does depend on w and scales with it, so we can conclude that camera coordinates must be in normal form (their w must be 1.0)

reconstructing circles from Bezier curves

I am trying to reconstruct original graphics primitives from Postscript/SVG paths. Thus an original circle is rendered (in SVG markup) as:
<path stroke-width="0.5" d="M159.679 141.309
C159.679 141.793 159.286 142.186 158.801 142.186
C158.318 142.186 157.925 141.793 157.925 141.309
C157.925 140.825 158.318 140.432 158.801 140.432
C159.286 140.432 159.679 140.825 159.679 141.309" />
This is an approximation using 4 Beziers curves to create a circle.In other places circular arcs are approximated by linked Bezier curves.
My question is whether there is an algorithm I can use to recognize this construct and reconstruct the "best" circle. I don't mind small errors - they will be second-order at worst.
UPDATE: Note that I don't know a priori that this is a circle or an arc - it could be anything. And there could be 2, 3 4 or possibly even more points on the curve. So I'd really like a function of the sort:
error = getCircleFromPath(path)
where error will give an early indication of whether this is likely to be a circle.
[I agree that if I know it's a circle it's an easier problem.]
UPDATE: #george goes some way towards answering my problem but I don't think it's the whole story.
After translation to the origin and normalization I appear to have the following four points on the curve:
point [0, 1] with control point at [+-d,1] // horizontal tangent
point [1, 0] with control point at [1,+-d] // vertical tangent
point [0, -1] with control point at [+-d,-1] // horizontal tangent
point [-1, 0] with control point at [-1,+-d] // vertical tangent
This guarantees that the tangent at each point is "parallel" to the path direction at the point. It also guarantees the symmetry (4-fold axis with reflection. But it does not guarantee a circle. For example a large value of d will give a rounded box and a small value a rounded diamond.
My value of d appears to be about 0.57. This might be 1/sqrt(3.) or it might be something else.It is this sort of relationship I am asking for.
#george gives midpoint of arc as;
{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}
so in my example (for 1,0 to 0,1) this would be:
[[1,0]+3[1,d]+3[d,1]+[0,1]] / 8
i.e.
[0.5+3d/8, 3d/8+0.5]
and if d =0.57, this gives 0.71, so maybe d is
(sqrt(0.5)-0.5)*8./3.
This holds for a square diamond, but for circular arcs the formula must be more general and I'd be grateful if anyone has it. For example, I am not familiar with Bezier math, so #george's formula was new to me
enter code here
Without doing all the math for you.. this may help:
there are always 4 control points on a bezier.
Your curve is 4 beziers linked together with points 1-4 , 4-7 , 7-10 , and 10-13 the control points
for each part. Points 1 , 4 , 7 and 10 (&13==1) lie exactly on the curve. To see if you have a nice circle calculate:
center = ( p1+p7 )/2 =( {159.679, 141.309} + {157.925, 141.309} ) / 2
= {158.802, 141.309}
verify you get the same result using points 4+10 -> {158.801, 141.309}
Once you know the center you can sample points along the curve and see if you have a constant distance.
If you only have a single bezier arc with 4 points a useful formula is that the midpoint is at
(p1 + 3 (p2 + p3) + p4)/8. So you can find the circle passing through three points:
{p1,(p1 + 3 (p2 + p3) + p4)/8,p4}
and again sample other points on the curve to decide if you indeed have a near circular arc.
Edit
the bezier formula is this:
x=(1-t)^3 p1 + 3 (1-t)^2 t p2 + 3 (1-t) t^2 p3 + t^3 p4 with parameter 0 < t < 1
so for example at t=1/4 you have
x=( 27 p1 + 27 p2 + 9 p3 + 1 p4 ) / 64
so once you find the center you can readily check a few points and calculate their distance.
I suspect if you only want to detect nearly exact circular arcs then checking two extra points with a tight tolerance will do the job. If you want to detect things that are approximately circular I would compute a bunch of points and use the average error as a criteria.
If all your elements are circle-like then you can just get the dimensions through path.getBBox() and generate a circle from there. In this case I'm considering ellipses, but you can easily translate it to actual circle elements:
var path = document.getElementById("circle_path");
var bbox = path.getBBox();
var rx = bbox.width/2;
var ry = bbox.height/2;
var cx = bbox.x + rx;
var cy = bbox.y + ry;
var ellipse = document.createElementNS(xmlns, "ellipse");
ellipse.setAttribute("fill", "none");
ellipse.setAttribute("stroke", "red");
ellipse.setAttribute("stroke-width", 0.1);
ellipse.setAttribute("cx", cx);
ellipse.setAttribute("cy", cy);
ellipse.setAttribute("rx", rx);
ellipse.setAttribute("ry", ry);
svg.appendChild(ellipse);
You can see a demo here:
http://jsfiddle.net/nwHm6/
The endpoints of the Bézier curves are probably on the circle. If so, it's easy to reconstruct the original circle.
Another possibility is to take the barycenter of the control points as the center of the circle because the control points are probably laid out symmetrically around the center. From the center, you get the radius as the average distance of the four control points closest to the center.
One can define an ellipse as a unit circle centred on (0,0), translated (2 params), scaled (2 params), and rotated (1 param). So on each arc take five points (t=0 ¼ ½ ¾ 1) and solve for these five parameters. Next take the in-between four points (t=⅛ ⅜ ⅝ ⅞), and test whether these lie on the same transformed circle. If yes, whoopee!, this is (part of) a transformed circle.
Immediately before and after might be another arc or arcn. Are these the same ellipse? If yes, and the subtended angles touch, then join together your descriptions of the pieces.

Clip matrix for 3D Perspective Projection

I am trying to create a simple 3D graphics engine and have found and used the equations I found here: http://en.wikipedia.org/wiki/3D_projection#cite_note-0. (I have calculations for Dx, Dy, Dz and Bx, By)
I works, but when I rotate the camera enough lines start flying all over the place and eventually you see the polygons that went off screen start to come back on the opposite side of the screen (you can go here: http://mobile.sheridanc.on.ca/~claassen/3d.html and use the W, A, S and D keys to rotate the camera to see what I'm talking about)
I read this discussion: How to convert a 3D point into 2D perspective projection? where he talked about using a clip matrix but Im still a little confused as to how exactly to use one. Also I'm not sure if I am using 'homogeneous coordinates' as described in the discussion.
After multiplying by the perspective projection matrix (aka clip matrix) you end up with a homogenious 4-vector [x,y,z,w]. This is called npc (normalized projection coordinates), and also called clip coordinates. To get the 2D coordinates on the screen you typically use something like
xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width
For points in front of the camera this gives you what you want. But points behind the camera will have w<0 and you will get values that map to valid screen coordinates even though the point is behind the camera. To avoid this you need to clip. Any vertex that has a w<0 needs to be clipped.
A quick thing to try is to just not draw any line if either vertex has w<0. This should fix the strange polygons that show up in your scene. But it will also remove some lines that should be visible.
TO completely fix the problem you need to clip all the lines which have one vertex in front of the camera and one vertex behind the camera. Clipping means cutting the line in half and throwing away the half that is behind the camera. The line is "clipped" by a plane that goes through the camera and is parallel to the display screen. The problem is to find the point on the line that corresponds to this plane (i.e. where the line intersects the plane). This will occur at the point on the line where w==0. You can find this point, but then when you try to find the screen coordinates
xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width
you end up dividing by 0 (w==0). This is the reason for the "near clipping plane". The near clipping plane is also parallel to the display screen but is in front of the camera (between the camera and the scene). The distance between the camera and the near clipping plane is the "near" parameter of the projection matrix:
[ 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 ]
To clip to the near plane you have to find the point on the line that intersects the near clipping plane. This is the point where w == near. So if you have a line with vertices v1,v2 where
v1 = [x1, y1, z1, w1]
v2 = [x2, y2, z2, w2]
you need to check if each vertex is in front of or behind the near clip plane. V1 is in front if w1 >= near and behind if w1 < near. If v1 and v2 are both in front then draw the line. If v1 and v2 are both behind then don't draw the line. If v1 is in front and v2 is behind then you need to find vc where the line intersects the near clip plane:
n = (w1 - near) / (w1 - w2)
xc = (n * x1) + ((1-n) * x2)
yc = (n * y1) + ((1-n) * y2)
zc = (n * z1) + ((1-n) * z2)
wc = near
vc = [xc, yc, zc, wc]
Now draw the line between v1 and vc.
This might be a misunderstanding of the terminology. The clip matrix is more appropriately known as a projection matrix. In OpenGL at least, the projection matrix transforms 4D homogeneous coordinates in view coordinate space (VCS) to clipping coordinate space (CCS). Projection from the CCS to normalized device coodinate space (NDCS) requires the perspective division, i.e., dividing each component by the W component. Clipping is correctly done before this step. So, a 'clipping matrix' doesn't remove the need to clip the geometry prior to projection. I hope I've understood you, and this doesn't sound condescending.
That said, I think you've obviously got the projection matrix right - it works. I suspect that the vertices passing behind the eye have negative W, which means they should be clipped; but I also suspect they have negative Z, so the division is yielding a positive Z value. If you really want to clip the geometry, rather than discard whole triangles, do a search for 'homogeneous clipping'. If you're not really working in 4D homogeneous space, you might start by looking at 'Sutherland-Hodgman' 3D clipping.

Resources