Elliptical rotation matrix? - c++

In C++ we can rotate a point about an arbitrary axis:
void radRotateAxis( float a, float b, float c, float theta )
{
float newX = (
x*( a*a*(1-cos(theta)) + cos(theta) ) +
y*( a*b*(1-cos(theta)) - c*sin(theta) ) +
z*( a*c*(1-cos(theta)) + b*sin(theta) ) );
float newY = (
x*( a*b*(1-cos(theta)) + c*sin(theta) ) +
y*( b*b*(1-cos(theta)) + cos(theta) ) +
z*( b*c*(1-cos(theta)) - a*sin(theta) ) );
float newZ = (
x*( a*c*(1-cos(theta)) - b*sin(theta) ) +
y*( b*c*(1-cos(theta)) + a*sin(theta) ) +
z*( c*c*(1-cos(theta)) + cos(theta) ) );
x = newX ;
y = newY ;
z = newZ ;
}
But as we walk theta 0 -> 2PI this takes the point around a "unit circle" around the axis you're rotating about
How can we make it so as theta 0 -> 2PI the results are about an ellipse of width a, height b?
I do not want to apply transformation matrices to the points after rotating them about the axis - what I'm looking for is an "elliptical" rotation matrix, if anyone knows of such a thing!

Define a matrix A to scale the target ellipse to a suitable unit circle.
Then the composition of A, the rotation matrix, and the inverse of A is your elliptical rotation matrix.

Related

How to get vertices for a sphere? [duplicate]

Are there any tutorials out there that explain how I can draw a sphere in OpenGL without having to use gluSphere()?
Many of the 3D tutorials for OpenGL are just on cubes. I have searched but most of the solutions to drawing a sphere are to use gluSphere(). There is also a site that has the code to drawing a sphere at this site but it doesn't explain the math behind drawing the sphere. I have also other versions of how to draw the sphere in polygon instead of quads in that link. But again, I don't understand how the spheres are drawn with the code. I want to be able to visualize so that I could modify the sphere if I need to.
One way you can do it is to start with a platonic solid with triangular sides - an octahedron, for example. Then, take each triangle and recursively break it up into smaller triangles, like so:
Once you have a sufficient amount of points, you normalize their vectors so that they are all a constant distance from the center of the solid. This causes the sides to bulge out into a shape that resembles a sphere, with increasing smoothness as you increase the number of points.
Normalization here means moving a point so that its angle in relation to another point is the same, but the distance between them is different.
Here's a two dimensional example.
A and B are 6 units apart. But suppose we want to find a point on line AB that's 12 units away from A.
We can say that C is the normalized form of B with respect to A, with distance 12. We can obtain C with code like this:
#returns a point collinear to A and B, a given distance away from A.
function normalize(a, b, length):
#get the distance between a and b along the x and y axes
dx = b.x - a.x
dy = b.y - a.y
#right now, sqrt(dx^2 + dy^2) = distance(a,b).
#we want to modify them so that sqrt(dx^2 + dy^2) = the given length.
dx = dx * length / distance(a,b)
dy = dy * length / distance(a,b)
point c = new point
c.x = a.x + dx
c.y = a.y + dy
return c
If we do this normalization process on a lot of points, all with respect to the same point A and with the same distance R, then the normalized points will all lie on the arc of a circle with center A and radius R.
Here, the black points begin on a line and "bulge out" into an arc.
This process can be extended into three dimensions, in which case you get a sphere rather than a circle. Just add a dz component to the normalize function.
If you look at the sphere at Epcot, you can sort of see this technique at work. it's a dodecahedron with bulged-out faces to make it look rounder.
I'll further explain a popular way of generating a sphere using latitude and longitude (another
way, icospheres, was already explained in the most popular answer at the time of this writing.)
A sphere can be expressed by the following parametric equation:
F(u, v) = [ cos(u)*sin(v)*r, cos(v)*r, sin(u)*sin(v)*r ]
Where:
r is the radius;
u is the longitude, ranging from 0 to 2π; and
v is the latitude, ranging from 0 to π.
Generating the sphere then involves evaluating the parametric function at fixed intervals.
For example, to generate 16 lines of longitude, there will be 17 grid lines along the u axis, with a step of
π/8 (2π/16) (the 17th line wraps around).
The following pseudocode generates a triangle mesh by evaluating a parametric function
at regular intervals (this works for any parametric surface function, not just spheres).
In the pseudocode below, UResolution is the number of grid points along the U axis
(here, lines of longitude), and VResolution is the number of grid points along the V axis
(here, lines of latitude)
var startU=0
var startV=0
var endU=PI*2
var endV=PI
var stepU=(endU-startU)/UResolution // step size between U-points on the grid
var stepV=(endV-startV)/VResolution // step size between V-points on the grid
for(var i=0;i<UResolution;i++){ // U-points
for(var j=0;j<VResolution;j++){ // V-points
var u=i*stepU+startU
var v=j*stepV+startV
var un=(i+1==UResolution) ? endU : (i+1)*stepU+startU
var vn=(j+1==VResolution) ? endV : (j+1)*stepV+startV
// Find the four points of the grid
// square by evaluating the parametric
// surface function
var p0=F(u, v)
var p1=F(u, vn)
var p2=F(un, v)
var p3=F(un, vn)
// NOTE: For spheres, the normal is just the normalized
// version of each vertex point; this generally won't be the case for
// other parametric surfaces.
// Output the first triangle of this grid square
triangle(p0, p2, p1)
// Output the other triangle of this grid square
triangle(p3, p1, p2)
}
}
The code in the sample is quickly explained. You should look into the function void drawSphere(double r, int lats, int longs):
void drawSphere(double r, int lats, int longs) {
int i, j;
for(i = 0; i <= lats; i++) {
double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats);
double z0 = sin(lat0);
double zr0 = cos(lat0);
double lat1 = M_PI * (-0.5 + (double) i / lats);
double z1 = sin(lat1);
double zr1 = cos(lat1);
glBegin(GL_QUAD_STRIP);
for(j = 0; j <= longs; j++) {
double lng = 2 * M_PI * (double) (j - 1) / longs;
double x = cos(lng);
double y = sin(lng);
glNormal3f(x * zr0, y * zr0, z0);
glVertex3f(r * x * zr0, r * y * zr0, r * z0);
glNormal3f(x * zr1, y * zr1, z1);
glVertex3f(r * x * zr1, r * y * zr1, r * z1);
}
glEnd();
}
}
The parameters lat defines how many horizontal lines you want to have in your sphere and lon how many vertical lines. r is the radius of your sphere.
Now there is a double iteration over lat/lon and the vertex coordinates are calculated, using simple trigonometry.
The calculated vertices are now sent to your GPU using glVertex...() as a GL_QUAD_STRIP, which means you are sending each two vertices that form a quad with the previously two sent.
All you have to understand now is how the trigonometry functions work, but I guess you can figure it out easily.
If you wanted to be sly like a fox you could half-inch the code from GLU. Check out the MesaGL source code (http://cgit.freedesktop.org/mesa/mesa/).
See the OpenGL red book: http://www.glprogramming.com/red/chapter02.html#name8
It solves the problem by polygon subdivision.
My example how to use 'triangle strip' to draw a "polar" sphere, it consists in drawing points in pairs:
const float PI = 3.141592f;
GLfloat x, y, z, alpha, beta; // Storage for coordinates and angles
GLfloat radius = 60.0f;
int gradation = 20;
for (alpha = 0.0; alpha < GL_PI; alpha += PI/gradation)
{
glBegin(GL_TRIANGLE_STRIP);
for (beta = 0.0; beta < 2.01*GL_PI; beta += PI/gradation)
{
x = radius*cos(beta)*sin(alpha);
y = radius*sin(beta)*sin(alpha);
z = radius*cos(alpha);
glVertex3f(x, y, z);
x = radius*cos(beta)*sin(alpha + PI/gradation);
y = radius*sin(beta)*sin(alpha + PI/gradation);
z = radius*cos(alpha + PI/gradation);
glVertex3f(x, y, z);
}
glEnd();
}
First point entered (glVertex3f) is as follows the parametric equation and the second one is shifted by a single step of alpha angle (from next parallel).
Although the accepted answer solves the question, there's a little misconception at the end. Dodecahedrons are (or could be) regular polyhedron where all faces have the same area. That seems to be the case of the Epcot (which, by the way, is not a dodecahedron at all). Since the solution proposed by #Kevin does not provide this characteristic I thought I could add an approach that does.
A good way to generate an N-faced polyhedron where all vertices lay in the same sphere and all its faces have similar area/surface is starting with an icosahedron and the iteratively sub-dividing and normalizing its triangular faces (as suggested in the accepted answer). Dodecahedrons, for instance, are actually truncated icosahedrons.
Regular icosahedrons have 20 faces (12 vertices) and can easily be constructed from 3 golden rectangles; it's just a matter of having this as a starting point instead of an octahedron. You may find an example here.
I know this is a bit off-topic but I believe it may help if someone gets here looking for this specific case.
Python adaptation of #Constantinius answer:
lats = 10
longs = 10
r = 10
for i in range(lats):
lat0 = pi * (-0.5 + i / lats)
z0 = sin(lat0)
zr0 = cos(lat0)
lat1 = pi * (-0.5 + (i+1) / lats)
z1 = sin(lat1)
zr1 = cos(lat1)
glBegin(GL_QUAD_STRIP)
for j in range(longs+1):
lng = 2 * pi * (j+1) / longs
x = cos(lng)
y = sin(lng)
glNormal(x * zr0, y * zr0, z0)
glVertex(r * x * zr0, r * y * zr0, r * z0)
glNormal(x * zr1, y * zr1, z1)
glVertex(r * x * zr1, r * y * zr1, r * z1)
glEnd()
void draw_sphere(float r)
{
float pi = 3.141592;
float di = 0.02;
float dj = 0.04;
float db = di * 2 * pi;
float da = dj * pi;
for (float i = 0; i < 1.0; i += di) //horizonal
for (float j = 0; j < 1.0; j += dj) //vertical
{
float b = i * 2 * pi; //0 to 2pi
float a = (j - 0.5) * pi; //-pi/2 to pi/2
//normal
glNormal3f(
cos(a + da / 2) * cos(b + db / 2),
cos(a + da / 2) * sin(b + db / 2),
sin(a + da / 2));
glBegin(GL_QUADS);
//P1
glTexCoord2f(i, j);
glVertex3f(
r * cos(a) * cos(b),
r * cos(a) * sin(b),
r * sin(a));
//P2
glTexCoord2f(i + di, j);//P2
glVertex3f(
r * cos(a) * cos(b + db),
r * cos(a) * sin(b + db),
r * sin(a));
//P3
glTexCoord2f(i + di, j + dj);
glVertex3f(
r * cos(a + da) * cos(b + db),
r * cos(a + da) * sin(b + db),
r * sin(a + da));
//P4
glTexCoord2f(i, j + dj);
glVertex3f(
r * cos(a + da) * cos(b),
r * cos(a + da) * sin(b),
r * sin(a + da));
glEnd();
}
}
One way is to make a quad that faces the camera and write a vertex and fragment shader that renders something that looks like a sphere. You could use equations for a circle/sphere that you can find on the internet.
One nice thing is that the silhouette of a sphere looks the same from any angle. However, if the sphere is not in the center of a perspective view, then it would appear perhaps more like an ellipse. You could work out the equations for this and put them in the fragment shading. Then the light shading needs to changed as the player moves, if you do indeed have a player moving in 3D space around the sphere.
Can anyone comment on if they have tried this or if it would be too expensive to be practical?

Calculate angle of rotation

I have a rectangle on the scene and I want to rotate it with mouse.
The rectangle has his own origin point. Clicking on the scene represents start of rotation and mouse moving represent angle of rotation.
where:
O - origin of rotation point
A - anchor point (saved in OnMousePress event)
C - current point (from OnMouseMove event)
so I calculate the angle in next steps:
Fistly, I get lengths of triangle sides:
AO = sqrt( (O.x - A.x)^2 + (O.y - A.y)^2 )
CO = sqrt( (O.x - C.x)^2 + (O.y - C.y)^2 )
AC = sqrt( (C.x - A.x)^2 + (C.y - A.y)^2 )
and then I calculate the angle (a):
a = arccos ( (AO^2 + CO^2 - AC^2) / (2 * AO * CO) )
it works, but this calculation look too complicated taking into account that I need to repeat on it all OnMouseMove call.
So my question - is there another way to calculate the angle? I write it in c++ so some code snippet will be apprecated.
You can find angle between vectors OA and OC through their scalar product and cross product:
OA = (OA.X, OA.Y) = (A.X-O.X, A.Y-O.Y)
OC = (OC.X, OC.Y) = (C.X-O.X, C.Y-O.Y)
SP = OA * OC = OA.X*OC.X+OA.Y*OC.Y
CP = OA x OC = OA.X*OC.Y-OA.Y*OC.X
Angle = atan2(CP, SP)
Example: O = (0,0), A = (-1, 0), C = (-2, 1)
SP = 2, CP = -1, Angle = -0.463
This method allows to avoid sqrt calculations, and determines rotation direction (unlike arccos)
You use a dot product of vectors OA and OC divided by their magnitude to calculate cosine of the angle and then use acos() function to find the angle.
float cosAngle = (x1 * x2 + y1 * y2) / sqrt(x1*x1 + y1*y1) * sqrt(x2*x2 + y2*y2);
float angle = acos(cosAngle);

Trying to use a rotation matrix, and failing

I have been trying to use a rotation matrix to rotate an image. Below is the code I've been using. I have been trying to do so for days now, and everytime it seems there is something wrong, but I can't see what I am doing wrong. For example, my image is getting slanted, instead of rotating...
The code below is divided in two parts: the actual rotation, and moving the picture upwards to make it appear in the correct spot (it needs to have all its point above 0 to be saved properly). It takes as input an array of pixels (containing position information (x, y), and colour information (r, g, b)), an image (used solely to get its pixel count, aka the array size, and the width), and a value in radians for the rotation.
The part responsible for the rotation itself is the one above the line, while the part below the line is responsible for calculating the lowest point in the image, and moving all pixels up or to the right so the all fit (I need still to implement a function to change the image size when an image is rotated by 45 degrees, or similar).
void Rotate( Pixel *p_pixelsToRotate, prg::Image* img, float rad )
{
int imgLength = img->getPixelCount();
int width = img->getWidth();
int x { 0 }, y { 0 };
for( int i = 0; i < imgLength; i++ )
{
x = p_pixelsToRotate[i].x;
y = p_pixelsToRotate[i].y;
p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );
p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
}
===========================================================================
Pixel* P1 = &p_pixelsToRotate[ width - 1 ]; // Definitions of these are in the supporting docs
Pixel* P3 = &p_pixelsToRotate[ imgLength - 1 ];
int xDiff = 0;
int yDiff = 0;
if( P1->x < 0 || P3->x < 0 )
{
(( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
}
if( P1->y < 0 || P3->y < 0 )
{
(( P1->y < P3->y )) ? ( yDiff = abs( P1->y )) : ( yDiff = abs( P3->y ));
}
for( int i = 0; i < imgLength; i++ )
{
p_pixelsToRotate[i].x += xDiff;
p_pixelsToRotate[i].y += yDiff;
}
}
I would prefer fixing this myself, but have been unable to do so for more than a week now. I don't see why the function is not rotating the position information for the array of input pixel. If someone could have a look, and maybe spot why my logic isn't working, I would be immensely grateful. Thank you.
Seems you just made a mistake in the rotation matrix itself:
p_pixelsToRotate[i].y = round( sin( rad ) * x + sin( rad ) * y );
^^^---------------change to cos
For one thing, this is a mistake:
p_pixelsToRotate[i].x = round( cos( rad ) * x - sin( rad ) * y );
p_pixelsToRotate[i].y = round( sin( rad ) * x + >>>sin<<<( rad ) * y );
The >>>sin<<< should be cos. This would explain getting a shear rather than a rotation.
Other comments: Storing pixel coordinates in bitmap data is an extremely expensive way to solve the problem of bitmap rotation. The better way is inverse transform sampling. With a source image X and wishing to rotate it with transform R to get Y, you are currently thinking
Y = R X
where X and Y have the pixel coordinates explicitly stored. To use inverse sampling, think instead of the same equation multiplied on both sides by the inverse of R.
R^(-1) Y = X
where the coordinates are implicit. That is, to produce Y[j][i], transform (j,i) with the inverse R^(-1) to get a coordinate (x,y) in the X image. Use this to sample the nearest pixel X[round(x)][round(y)] in X and assign that as Y[j][i].
(Actually, rather than simple rounding, a more sophisticated algorithm will take a weighted average of the X pixels around (x,y) to get a smoother result. How to choose the weights is a big additional topic.)
After you have this working, you can go a step farther. Instead of doing a full matrix-vector multiplication for each pixel, some algebra will show that the previous sampling coordinate can be updated to get an adjacent one (next to the right or left, up or down) with just a couple of additions. This speeds things up considerably.
The inverse of a rotation is trivial to compute! Just negate the rotation angle.
A last note is that your use of ternary operators o ? o : o to select assignments is truly terrible style. Instead of this:
(( P1->x < P3->x )) ? ( xDiff = abs( P1->x )) : ( xDiff = abs( P3->x ));
say
xDiff = ( P1->x < P3->x ) ? abs( P1->x ) : abs( P3->x );

Drawing Sphere in OpenGL without using gluSphere()?

Are there any tutorials out there that explain how I can draw a sphere in OpenGL without having to use gluSphere()?
Many of the 3D tutorials for OpenGL are just on cubes. I have searched but most of the solutions to drawing a sphere are to use gluSphere(). There is also a site that has the code to drawing a sphere at this site but it doesn't explain the math behind drawing the sphere. I have also other versions of how to draw the sphere in polygon instead of quads in that link. But again, I don't understand how the spheres are drawn with the code. I want to be able to visualize so that I could modify the sphere if I need to.
One way you can do it is to start with a platonic solid with triangular sides - an octahedron, for example. Then, take each triangle and recursively break it up into smaller triangles, like so:
Once you have a sufficient amount of points, you normalize their vectors so that they are all a constant distance from the center of the solid. This causes the sides to bulge out into a shape that resembles a sphere, with increasing smoothness as you increase the number of points.
Normalization here means moving a point so that its angle in relation to another point is the same, but the distance between them is different.
Here's a two dimensional example.
A and B are 6 units apart. But suppose we want to find a point on line AB that's 12 units away from A.
We can say that C is the normalized form of B with respect to A, with distance 12. We can obtain C with code like this:
#returns a point collinear to A and B, a given distance away from A.
function normalize(a, b, length):
#get the distance between a and b along the x and y axes
dx = b.x - a.x
dy = b.y - a.y
#right now, sqrt(dx^2 + dy^2) = distance(a,b).
#we want to modify them so that sqrt(dx^2 + dy^2) = the given length.
dx = dx * length / distance(a,b)
dy = dy * length / distance(a,b)
point c = new point
c.x = a.x + dx
c.y = a.y + dy
return c
If we do this normalization process on a lot of points, all with respect to the same point A and with the same distance R, then the normalized points will all lie on the arc of a circle with center A and radius R.
Here, the black points begin on a line and "bulge out" into an arc.
This process can be extended into three dimensions, in which case you get a sphere rather than a circle. Just add a dz component to the normalize function.
If you look at the sphere at Epcot, you can sort of see this technique at work. it's a dodecahedron with bulged-out faces to make it look rounder.
I'll further explain a popular way of generating a sphere using latitude and longitude (another
way, icospheres, was already explained in the most popular answer at the time of this writing.)
A sphere can be expressed by the following parametric equation:
F(u, v) = [ cos(u)*sin(v)*r, cos(v)*r, sin(u)*sin(v)*r ]
Where:
r is the radius;
u is the longitude, ranging from 0 to 2π; and
v is the latitude, ranging from 0 to π.
Generating the sphere then involves evaluating the parametric function at fixed intervals.
For example, to generate 16 lines of longitude, there will be 17 grid lines along the u axis, with a step of
π/8 (2π/16) (the 17th line wraps around).
The following pseudocode generates a triangle mesh by evaluating a parametric function
at regular intervals (this works for any parametric surface function, not just spheres).
In the pseudocode below, UResolution is the number of grid points along the U axis
(here, lines of longitude), and VResolution is the number of grid points along the V axis
(here, lines of latitude)
var startU=0
var startV=0
var endU=PI*2
var endV=PI
var stepU=(endU-startU)/UResolution // step size between U-points on the grid
var stepV=(endV-startV)/VResolution // step size between V-points on the grid
for(var i=0;i<UResolution;i++){ // U-points
for(var j=0;j<VResolution;j++){ // V-points
var u=i*stepU+startU
var v=j*stepV+startV
var un=(i+1==UResolution) ? endU : (i+1)*stepU+startU
var vn=(j+1==VResolution) ? endV : (j+1)*stepV+startV
// Find the four points of the grid
// square by evaluating the parametric
// surface function
var p0=F(u, v)
var p1=F(u, vn)
var p2=F(un, v)
var p3=F(un, vn)
// NOTE: For spheres, the normal is just the normalized
// version of each vertex point; this generally won't be the case for
// other parametric surfaces.
// Output the first triangle of this grid square
triangle(p0, p2, p1)
// Output the other triangle of this grid square
triangle(p3, p1, p2)
}
}
The code in the sample is quickly explained. You should look into the function void drawSphere(double r, int lats, int longs):
void drawSphere(double r, int lats, int longs) {
int i, j;
for(i = 0; i <= lats; i++) {
double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats);
double z0 = sin(lat0);
double zr0 = cos(lat0);
double lat1 = M_PI * (-0.5 + (double) i / lats);
double z1 = sin(lat1);
double zr1 = cos(lat1);
glBegin(GL_QUAD_STRIP);
for(j = 0; j <= longs; j++) {
double lng = 2 * M_PI * (double) (j - 1) / longs;
double x = cos(lng);
double y = sin(lng);
glNormal3f(x * zr0, y * zr0, z0);
glVertex3f(r * x * zr0, r * y * zr0, r * z0);
glNormal3f(x * zr1, y * zr1, z1);
glVertex3f(r * x * zr1, r * y * zr1, r * z1);
}
glEnd();
}
}
The parameters lat defines how many horizontal lines you want to have in your sphere and lon how many vertical lines. r is the radius of your sphere.
Now there is a double iteration over lat/lon and the vertex coordinates are calculated, using simple trigonometry.
The calculated vertices are now sent to your GPU using glVertex...() as a GL_QUAD_STRIP, which means you are sending each two vertices that form a quad with the previously two sent.
All you have to understand now is how the trigonometry functions work, but I guess you can figure it out easily.
If you wanted to be sly like a fox you could half-inch the code from GLU. Check out the MesaGL source code (http://cgit.freedesktop.org/mesa/mesa/).
See the OpenGL red book: http://www.glprogramming.com/red/chapter02.html#name8
It solves the problem by polygon subdivision.
My example how to use 'triangle strip' to draw a "polar" sphere, it consists in drawing points in pairs:
const float PI = 3.141592f;
GLfloat x, y, z, alpha, beta; // Storage for coordinates and angles
GLfloat radius = 60.0f;
int gradation = 20;
for (alpha = 0.0; alpha < GL_PI; alpha += PI/gradation)
{
glBegin(GL_TRIANGLE_STRIP);
for (beta = 0.0; beta < 2.01*GL_PI; beta += PI/gradation)
{
x = radius*cos(beta)*sin(alpha);
y = radius*sin(beta)*sin(alpha);
z = radius*cos(alpha);
glVertex3f(x, y, z);
x = radius*cos(beta)*sin(alpha + PI/gradation);
y = radius*sin(beta)*sin(alpha + PI/gradation);
z = radius*cos(alpha + PI/gradation);
glVertex3f(x, y, z);
}
glEnd();
}
First point entered (glVertex3f) is as follows the parametric equation and the second one is shifted by a single step of alpha angle (from next parallel).
Although the accepted answer solves the question, there's a little misconception at the end. Dodecahedrons are (or could be) regular polyhedron where all faces have the same area. That seems to be the case of the Epcot (which, by the way, is not a dodecahedron at all). Since the solution proposed by #Kevin does not provide this characteristic I thought I could add an approach that does.
A good way to generate an N-faced polyhedron where all vertices lay in the same sphere and all its faces have similar area/surface is starting with an icosahedron and the iteratively sub-dividing and normalizing its triangular faces (as suggested in the accepted answer). Dodecahedrons, for instance, are actually truncated icosahedrons.
Regular icosahedrons have 20 faces (12 vertices) and can easily be constructed from 3 golden rectangles; it's just a matter of having this as a starting point instead of an octahedron. You may find an example here.
I know this is a bit off-topic but I believe it may help if someone gets here looking for this specific case.
Python adaptation of #Constantinius answer:
lats = 10
longs = 10
r = 10
for i in range(lats):
lat0 = pi * (-0.5 + i / lats)
z0 = sin(lat0)
zr0 = cos(lat0)
lat1 = pi * (-0.5 + (i+1) / lats)
z1 = sin(lat1)
zr1 = cos(lat1)
glBegin(GL_QUAD_STRIP)
for j in range(longs+1):
lng = 2 * pi * (j+1) / longs
x = cos(lng)
y = sin(lng)
glNormal(x * zr0, y * zr0, z0)
glVertex(r * x * zr0, r * y * zr0, r * z0)
glNormal(x * zr1, y * zr1, z1)
glVertex(r * x * zr1, r * y * zr1, r * z1)
glEnd()
void draw_sphere(float r)
{
float pi = 3.141592;
float di = 0.02;
float dj = 0.04;
float db = di * 2 * pi;
float da = dj * pi;
for (float i = 0; i < 1.0; i += di) //horizonal
for (float j = 0; j < 1.0; j += dj) //vertical
{
float b = i * 2 * pi; //0 to 2pi
float a = (j - 0.5) * pi; //-pi/2 to pi/2
//normal
glNormal3f(
cos(a + da / 2) * cos(b + db / 2),
cos(a + da / 2) * sin(b + db / 2),
sin(a + da / 2));
glBegin(GL_QUADS);
//P1
glTexCoord2f(i, j);
glVertex3f(
r * cos(a) * cos(b),
r * cos(a) * sin(b),
r * sin(a));
//P2
glTexCoord2f(i + di, j);//P2
glVertex3f(
r * cos(a) * cos(b + db),
r * cos(a) * sin(b + db),
r * sin(a));
//P3
glTexCoord2f(i + di, j + dj);
glVertex3f(
r * cos(a + da) * cos(b + db),
r * cos(a + da) * sin(b + db),
r * sin(a + da));
//P4
glTexCoord2f(i, j + dj);
glVertex3f(
r * cos(a + da) * cos(b),
r * cos(a + da) * sin(b),
r * sin(a + da));
glEnd();
}
}
One way is to make a quad that faces the camera and write a vertex and fragment shader that renders something that looks like a sphere. You could use equations for a circle/sphere that you can find on the internet.
One nice thing is that the silhouette of a sphere looks the same from any angle. However, if the sphere is not in the center of a perspective view, then it would appear perhaps more like an ellipse. You could work out the equations for this and put them in the fragment shading. Then the light shading needs to changed as the player moves, if you do indeed have a player moving in 3D space around the sphere.
Can anyone comment on if they have tried this or if it would be too expensive to be practical?

Rotating a point about another point (2D)

I'm trying to make a card game where the cards fan out. Right now to display it Im using the Allegro API which has a function:
al_draw_rotated_bitmap(OBJECT_TO_ROTATE,CENTER_X,CENTER_Y,X
,Y,DEGREES_TO_ROTATE_IN_RADIANS);
so with this I can make my fan effect easily. The problem is then knowing which card is under the mouse. To do this I thought of doing a polygon collision test. I'm just not sure how to rotate the 4 points on the card to make up the polygon. I basically need to do the same operation as Allegro.
for example, the 4 points of the card are:
card.x
card.y
card.x + card.width
card.y + card.height
I would need a function like:
POINT rotate_point(float cx,float cy,float angle,POINT p)
{
}
Thanks
First subtract the pivot point (cx,cy), then rotate it (counter clock-wise), then add the point again.
Untested:
POINT rotate_point(float cx,float cy,float angle,POINT p)
{
float s = sin(angle);
float c = cos(angle);
// translate point back to origin:
p.x -= cx;
p.y -= cy;
// rotate point
float xnew = p.x * c - p.y * s;
float ynew = p.x * s + p.y * c;
// translate point back:
p.x = xnew + cx;
p.y = ynew + cy;
return p;
}
If you rotate point (px, py) around point (ox, oy) by angle theta you'll get:
p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox
p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy
this is an easy way to rotate a point in 2D.
The coordinate system on the screen is left-handed, i.e. the x coordinate increases from left to right and the y coordinate increases from top to bottom. The origin, O(0, 0) is at the upper left corner of the screen.
A clockwise rotation around the origin of a point with coordinates (x, y) is given by the following equations:
where (x', y') are the coordinates of the point after rotation and angle theta, the angle of rotation (needs to be in radians, i.e. multiplied by: PI / 180).
To perform rotation around a point different from the origin O(0,0), let's say point A(a, b) (pivot point). Firstly we translate the point to be rotated, i.e. (x, y) back to the origin, by subtracting the coordinates of the pivot point, (x - a, y - b).
Then we perform the rotation and get the new coordinates (x', y') and finally we translate the point back, by adding the coordinates of the pivot point to the new coordinates (x' + a, y' + b).
Following the above description:
a 2D clockwise theta degrees rotation of point (x, y) around point (a, b) is:
Using your function prototype: (x, y) -> (p.x, p.y); (a, b) -> (cx, cy); theta -> angle:
POINT rotate_point(float cx, float cy, float angle, POINT p){
return POINT(cos(angle) * (p.x - cx) - sin(angle) * (p.y - cy) + cx,
sin(angle) * (p.x - cx) + cos(angle) * (p.y - cy) + cy);
}
float s = sin(angle); // angle is in radians
float c = cos(angle); // angle is in radians
For clockwise rotation :
float xnew = p.x * c + p.y * s;
float ynew = -p.x * s + p.y * c;
For counter clockwise rotation :
float xnew = p.x * c - p.y * s;
float ynew = p.x * s + p.y * c;
This is the answer by Nils Pipenbrinck, but implemented in c# fiddle.
https://dotnetfiddle.net/btmjlG
using System;
public class Program
{
public static void Main()
{
var angle = 180 * Math.PI/180;
Console.WriteLine(rotate_point(0,0,angle,new Point{X=10, Y=10}).Print());
}
static Point rotate_point(double cx, double cy, double angle, Point p)
{
double s = Math.Sin(angle);
double c = Math.Cos(angle);
// translate point back to origin:
p.X -= cx;
p.Y -= cy;
// rotate point
double Xnew = p.X * c - p.Y * s;
double Ynew = p.X * s + p.Y * c;
// translate point back:
p.X = Xnew + cx;
p.Y = Ynew + cy;
return p;
}
class Point
{
public double X;
public double Y;
public string Print(){
return $"{X},{Y}";
}
}
}
Ps: Apparently I can’t comment, so I’m obligated to post it as an answer ...
I struggled while working MS OCR Read API which returns back angle of rotation in range (-180, 180]. So I have to do an extra step of converting negative angles to positive. I hope someone struggling with point rotation with negative or positive angles can use the following.
def rotate(origin, point, angle):
"""
Rotate a point counter-clockwise by a given angle around a given origin.
"""
# Convert negative angles to positive
angle = normalise_angle(angle)
# Convert to radians
angle = math.radians(angle)
# Convert to radians
ox, oy = origin
px, py = point
# Move point 'p' to origin (0,0)
_px = px - ox
_py = py - oy
# Rotate the point 'p'
qx = (math.cos(angle) * _px) - (math.sin(angle) * _py)
qy = (math.sin(angle) * _px) + (math.cos(angle) * _py)
# Move point 'p' back to origin (ox, oy)
qx = ox + qx
qy = oy + qy
return [qx, qy]
def normalise_angle(angle):
""" If angle is negative then convert it to positive. """
if (angle != 0) & (abs(angle) == (angle * -1)):
angle = 360 + angle
return angle