I'm having little trouble whit trying to compare rotated 2D Quads coordinates to rotated x and y coordinates. I'm trying to determine if mouse was clicked inside the quad.
1) the rot's are this classes objects: (note : the operator << is overloaded for the use of the rotate coords func)
class Vector{
private:
std::vector <float> Vertices;
public:
Vector(float, float);
float GetVertice(unsigned int);
void SetVertice(unsigned int, float);
std::vector<float> operator <<(double);
};
Vector::Vector(float X,float Y){
Vertices.push_back(X);
Vertices.push_back(Y);
}
float Vector::GetVertice(unsigned int Index){
return Vertices.at(Index);
}
void Vector::SetVertice(unsigned int Index,float NewVertice){
Vertices.at(Index) = NewVertice;
}
//Return rotated coords:D
std::vector <float> Vector::operator <<(double Angle){
std::vector<float> Temp;
Temp.push_back(Vertices.at(0) * cos(Angle) - Vertices.at(1) * sin(Angle));
Temp.push_back(Vertices.at(0) * sin(Angle) + Vertices.at(1) * cos(Angle));
return Temp;
}
2) Comparasion and rotation of the coordinates THE NEW VERSION
Vector Rot1(x,y),Rot3(x,y);
double Angle;
std::vector <float> result1,result3;
Rot3.SetVertice(0,NewQuads.at(Index).GetXpos() + NewQuads.at(Index).GetWidth());
Rot3.SetVertice(1,NewQuads.at(Index).GetYpos() + NewQuads.at(Index).GetHeight());
Angle = NewQuads.at(Index).GetRotation();
result1 = Rot1 << Angle; // Rotate the mouse x and y
result3 = Rot3 << Angle; // Rotate the Quad x and y
//.at(0) = x and .at(1)=y
if(result1.at(0) >= result3.at(0) - NewQuads.at(Index).GetWidth() && result1.at(0) <= result3.at(0) ){
if(result1.at(1) >= result3.at(1) - NewQuads.at(Index).GetHeight() && result1.at(1) <= result3.at(1) ){
when i run this it works perfectly at 0 angle but when you rotate the quad, it fails.
and by failing I mean the activation area seem to just disappear.
am I doing the rotation of the coordinates correctly? or is it the comparison?
if it's the comparison how would you do it properly, I have tried changing the if's but whit out any luck...
edit
the drawing of the quad(Happens before the testing):
void Quad::Render()
{
if(!CheckIfOutOfScreen()){
glPushMatrix();
glLoadIdentity();
glTranslatef(Xpos ,Ypos ,0.f);
glRotatef(Rotation,0.f,0.f,1.f); // same rotation is used for the testing later...
glBegin(GL_QUADS);
glVertex2f(Zwidth,Zheight);
glVertex2f(Width,Zheight);
glVertex2f(Width,Height);
glVertex2f(Zwidth,Height);
glEnd();
if(State != NOT_ACTIVE)
RenderShapeTools();
glPopMatrix();
}
}
basicly I'm trying to test if mouse was clicked inside this quad:
Image
There is more than one way to achieve what you want, But from the image you posted I assume you want to draw to a surface the same size as your screen (or window) using only 2D graphics.
As you know in 3D graphics we talk about 3 coordinate references. The first is the coordinate reference of the object or model to be drawn, the second is the coordinate reference of the camera or view and the third is the coordinate reference of the screen.
In OpenGL the first two coordinate references are established through the MODELVIEW matrix and the third is achieved by the PROJECTION matrix and the viewport transformation.
In your case you want to rotate a quad and place it somewhere on the screen. Your quad has it's own model coordinates. Let's assume that for this specific 2D quad the origin is at the center of the quad and it has the dimensions of 5 by 5. Also let's assume that if we look to the center of the quad then the X axis points to the RIGHT, the Y axis points UP and the Z axis points towards the viewer.
The unrotated coordinates of the quad will be (from bottom left clockwise): (-2.5,-2.5,0), (-2.5,2.5,0), (2.5,2.5,0), (2.5,-2.5,0)
Now we want to have a camera and projection matrices and viewport so to simulate a 2D surface with known dimensions.
//Assume WinW contains the window width and WinH contains the windows height
glViewport(0,0,WinW,WinH);//Set the viewport to the whole window
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, WinW, WinH, 0, 0, 1);//Set the projection matrix to perform a 2D orthogonal projection
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();//Set the camera matrix to be the Identity matrix
You are now ready to draw your quad an this 2D surface with dimensions WinW, WinH. In this context if you just draw your quad using it's current vertices you will have the quad drawn with it's center at the bottom left of the window with each side measuring 5 pixels so you will actually see only quarter of a quad. If you want to rotate and move it you will do something like this:
//Prepare matrices as shown above
//Viewport coordinates range from bottom left (0,0) to top right (WinW,WinH)
float dX = CenterOfQuadInViewportCoordinatesX, dY = CenterOfQuadInViewportCoordinatesY;
float rotA = QuadRotationAngleAroundZAxisInDegrees;
float verticesX[4] = {-2.5,-2.5,2.5,2.5};
float verticesY[4] = {-2.5,2.5,2.5,-2.5};
//Remember that rotate is done first and translation second
glTranslatef(dX,dY,0);//Move the quad to the desired location in the viewport
glRotate(rotA, 0,0,1);//Rotate the quad around it's origin
glBegin(GL_QUADS);
glVertex2f(verticesX[0], veriticesY[0]);
glVertex2f(verticesX[1], veriticesY[1]);
glVertex2f(verticesX[2], veriticesY[2]);
glVertex2f(verticesX[3], veriticesY[3]);
glEnd();
Now you want to know whether the click of the mouse was within the rendered quad.
Whereas the viewport coordinates start from the bottom left the window coordinates start from the top left. So when you get the mouse coordinates you have to translate them to viewport coordinates in the following way:
float mouseViewportX = mouseX, mouseViewportY = WinH - mouseY - 1;
Once you have the mouse location in viewport coordinates you need to transform it to model coordinates in the following way (Please double check the calculations since I generally use my own matrix library for that and don't calculate it by hand):
//Translate the mouse location to model coordinates reference
mouseViewportX -= dX, mouseViewportY -= dY;
//Unrotate the mouse location
float invRotARad = -rotA*DEG_TO_RAD;
float sinRA = sin(invRotARad), cosRA = cos(invRotA);
float mouseInModelX = cosRA*mouseViewportX - sinRA*mouseViewportY;
float mouseInModelY = sinRA*mouseViewportX + cosRA*mouseViewportY;
And now you can finally check if the mouse falls within the quad - as you can see this is done in quad coordinates:
bool mouseInQuad = mouseInModelX > verticesX[0] && mouseInModelY < verticesX[1] &&
mouseInModelY > verticesY[0] && mouseInModelY < verticesY[1];
Hope I didn't make too many mistakes and this puts you on the right track. If you want to deal with more complex cases and 3D then you should have a look at gluUnproject (maybe you will want to implement your own) and for even more complex scenes you may need to use a stencil or depth buffers
Related
After picking an object with the mouse, I want to be able to move the object using the mouse. First, I translate mouse position to world position, and use glReadPixels() to read the depth of the object as z's:
double xpos, ypos, zpos;
glfwGetCursorPos(window_ptr, &xpos, &ypos);
float xPercent = (xpos + 0.5f) / scr_width_ * 2.0f - 1; // range is -1 to +1
float yPercent = (ypos + 0.5f) / scr_height_ * 2.0f - 1; // range is -1 to +1
yPercent = -yPercent;
glReadPixels(xpos, scr_height_ - ypos - 1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zPercent);
then we move the mouse until we want to release the mouse.
last_position = (xPercent, yPercent, zPercent);
Finally we use the same value as z's value and calculate the x's world position and y's position:
current_position = (xPercent, yPercent, zPercent);
then we translate the object model:
model = glm::translate(model, current_position - last_postion);
the issue is:
the object's speed is not same as mouse's.
waiting for your answer.
The problem is caused by the difference in coordinate systems between the screen and the world. Your cursor position is in "percent" (fraction of the screen width), but your objects are likely placed in some other coordinate system that is determined by your projection matrix (for example, in meters). Unless you are using an orthographic projection and the world-space coordinates of the object are in the same space as the screen-space coordinates, you will get different motion.
For example, even if you had an orthographic projection, it may be configured such that the screen maps to a region of game world that is 20 meters wide, so moving your mouse anywhere within the range [-1, 1] (across the full width of the screen) will only translate to the object moving over 1/10th of the screen.
Furthermore, you may be working with a perspective projection. In that case, not only will your world coordinates differ from the screen coordinates, but there is actually a nonlinear transformation between the screen coordinates and the world coordinates that will cause the object's motion to be distorted near the edges of the screen. You can correct for this by un-projecting your mouse cursor's screen-space coordinates back into world coordinates using glm::unproject. Here is a good explanation of this process.
I'm trying to make a 2D game using DirectX 11 and I get distortion issues when I rotate the camera
By rotating the camera I mean rotating it about its Z axis with the X axis being left/right on the screen, the Y axis being up/down on the screen, and the Z axis protruding from the screen. so when I rotate the camera, the rest of the world should appear to be orbiting around the center of the screen
Here I have a perfectly square sprite
and when I rotate the camera it becomes stretched
note this doesn't happen when I rotate the sprite itself, only the camera
my current setup with my camera is
void Camera::SetOrthoMatrix(float width, float height, float nearZ, float farZ) //called when initializing the camera
{
orthoMatrix=XMMatrixOrthographicOffCenterLH(0.0f, width, 0.0f, height, nearZ, farZ);
}
void Camera::UpdateMatrix() //called whenever the camera's position or rotation changes
{
worldMatrix = XMMatrixTranslation(-pos.x, -pos.y, 0.0f) * XMMatrixRotationZ(rot);
}
XMMatrix Camera::GetViewMatrix()
{
return orthoMatrix * worldMatrix
}
My sprite class just takes it's own world matrix and multiplies it by camera.GetViewMatrix() and then I draw the sprite. I'm fairly certain that the distortion is caused by the orthographic matrix, but I can't figure out a way to fix it.
I figured it out by changing XMMatrixOrthographicOffCenterLH to XMMatrixOrthograpghicLH. then reordering the matrix multiplication from sprite, orthographic, camera to sprite, camera, orthographic.
this changes the coordinate system a little, before I had 0,0 be the bottom left corner of the screen but with XMMatrixOrthograpghicLH the origin is at the center of the screen. It's not quite what I wanted but it's a minor inconvenience.
Prologue
This Q&A is a remake of:
How to highlight 3D perspective camera view (frustrum) on topside 2D minimap?
which was closed (and failed first reopening cycle) due to lack of info and no response of the original author. However I think this is an interesting question though so I decided to Ask&Answer this myself (this time with all the needed specs).
Question
Let assume our world is a uniform rectangular square grid (represented by 2D array of tiles) mapped on a plane (let say plane XY (Z=0.0) for simplicity) and is rendered with perspective projection. like this:
How to map the perspective frustrum (visible part of the map/plane) to the red colored polygonal shape on the minimap ?
To be more universal let assume this as input:
plane (Z=0.0) defined as start point p0 and two basis vectors du,dv which maps the 2D map array of tiles to 3D ...
ModelView matrix and Perspective matrix used
And wanted output:
4 point polygon (on minimap) representing the visible part of out plane
Limitations (to more or less match the original question):
use C++
old style OpenGL (GL,GLU)
no 3th party lib for vector/matrix math
So what we want is to obtain the 4 intersection points between our plane (Z=0.0) and camera frustrum. So the idea is to cast 4 rays (one for each edge of frustrum) from the camera focal point and simply compute the ray/plane intersection. As the plane is Z=0.0 the intersection point has Z=0.0 too so the intersection is quite easy to compute.
Cast ray for each corner/edge
from camera focal point to screen corner (in screen space)
and convert it to world global coordinates (by reverting perspective and using inverse modelview matrix it is described later). The ray should be in form:
p(t) = p + dp*t
where p is the focal point and dp is direction vector (does not need to be normalized)
compute the intersection with XY plane (Z=0.0)
As the z=0.0 then:
0 = p.z + dp.z*t
t = -p.z/dp.z
so we can compute the intersection point directly.
convert 3D intersection points to u,v inside map
for that simple dot product is enough. So if p is our intersection point then:
u = dot(p-p0,du)
v = dot(p-p0,dv)
where u,v are coordinates in our 2D map array or minimap. In case your u,v are axis aligned then you can use directly (p.x-p0.x,p.y-p0.y) without any dot product
How to convert point p from camera coordinates to global world coordinates:
revert perspective
first obtain perspective matrix parameters
double per[16],zNear,zFar,fx,fy;
glGetDoublev(GL_PROJECTION_MATRIX,per);
zFar =0.5*per[14]*(1.0-((per[10]-1.0)/(per[10]+1.0)));
zNear=zFar*(per[10]+1.0)/(per[10]-1.0);
fx=per[0];
fy=per[5];
This will give you the frustrums near and far planes and scaling for x,y axises. Now reverting perspective is simply inverting the perspective divide like this:
p[1]*=(-p[2]/fy); // apply inverse of perspective
p[0]*=(-p[2]/fx);
The znear and zfar are needed for casting the rays. For more info see:
depth buffer got by glReadPixels is always 1
global world coordinates
simply use inverse of ModelView matrix on our p. So first obtain the matrix:
double cam[16];
glGetDoublev(GL_MODELVIEW_MATRIX,cam);
As inverse you can use my matrix_inv so now the final step is:
p = Inverse(cam)*p;
but do not forget that p must be homogenuous so (x,y,z,1) for points and (x,y,z,0) for vectors.
Look here if you lack the background knowledge or need vector/matrix math:
Understanding 4x4 homogenous transform matrices
Here Small C++ example of this:
//---------------------------------------------------------------------------
void matrix_mul_vector(double *c,double *a,double *b)
{
double q[3];
q[0]=(a[ 0]*b[0])+(a[ 4]*b[1])+(a[ 8]*b[2])+(a[12]);
q[1]=(a[ 1]*b[0])+(a[ 5]*b[1])+(a[ 9]*b[2])+(a[13]);
q[2]=(a[ 2]*b[0])+(a[ 6]*b[1])+(a[10]*b[2])+(a[14]);
for(int i=0;i<3;i++) c[i]=q[i];
}
//---------------------------------------------------------------------------
void matrix_inv(double *a,double *b) // a[16] = Inverse(b[16])
{
double x,y,z;
// transpose of rotation matrix
a[ 0]=b[ 0];
a[ 5]=b[ 5];
a[10]=b[10];
x=b[1]; a[1]=b[4]; a[4]=x;
x=b[2]; a[2]=b[8]; a[8]=x;
x=b[6]; a[6]=b[9]; a[9]=x;
// copy projection part
a[ 3]=b[ 3];
a[ 7]=b[ 7];
a[11]=b[11];
a[15]=b[15];
// convert origin: new_pos = - new_rotation_matrix * old_pos
x=(a[ 0]*b[12])+(a[ 4]*b[13])+(a[ 8]*b[14]);
y=(a[ 1]*b[12])+(a[ 5]*b[13])+(a[ 9]*b[14]);
z=(a[ 2]*b[12])+(a[ 6]*b[13])+(a[10]*b[14]);
a[12]=-x;
a[13]=-y;
a[14]=-z;
}
//---------------------------------------------------------------------------
void draw_map()
{
int i,j;
double u,v,p[3],dp[3];
// here 3D view must be already set (modelview,projection)
glDisable(GL_CULL_FACE);
// [draw 3D map]
const int n=30; // map size
double p0[3]={0.0,0.0,0.0}; // map start point
double du[3]={1.0,0.0,0.0}; // map u step (size of grid = 1.0 )
double dv[3]={0.0,1.0,0.0}; // map v step (size of grid = 1.0 )
glColor3f(0.5,0.7,1.0);
glBegin(GL_LINES);
for (j=0;j<=n;j++)
{
for (i=0;i<3;i++) p[i]=p0[i]+(double(j)*du[i])+(double(0)*dv[i]); glVertex3dv(p);
for (i=0;i<3;i++) p[i]=p0[i]+(double(j)*du[i])+(double(n)*dv[i]); glVertex3dv(p);
for (i=0;i<3;i++) p[i]=p0[i]+(double(0)*du[i])+(double(j)*dv[i]); glVertex3dv(p);
for (i=0;i<3;i++) p[i]=p0[i]+(double(n)*du[i])+(double(j)*dv[i]); glVertex3dv(p);
}
glEnd();
// [compute trapeze points]
double cam[16],per[16],pt[4][3],zNear,zFar,fx,fy;
glGetDoublev(GL_PROJECTION_MATRIX,per); // obtain matrices
glGetDoublev(GL_MODELVIEW_MATRIX,cam);
matrix_inv(cam,cam);
zFar =0.5*per[14]*(1.0-((per[10]-1.0)/(per[10]+1.0)));
zNear=zFar*(per[10]+1.0)/(per[10]-1.0);
fx=per[0];
fy=per[5];
for (j=0;j<4;j++) // 4 corners
{
for (i=0;i<3;i++) dp[i]=0.0; // cast ray from camera focus dp
if (j==0) { p[0]=-1.0; p[1]=-1.0; } // to screen corner p
if (j==1) { p[0]=-1.0; p[1]=+1.0; }
if (j==2) { p[0]=+1.0; p[1]=+1.0; }
if (j==3) { p[0]=+1.0; p[1]=-1.0; }
p[2]=zNear; // start position at screen plane
p[1]*=(-p[2]/fy); // apply inverse of perspective
p[0]*=(-p[2]/fx);
// transform to worlds global coordinates
matrix_mul_vector( p,cam, p);
matrix_mul_vector(dp,cam,dp);
// compute intersection of ray and XY plane (z=0) as pt[j] (i exploited the fact that the intersection have z=0.0 for arbitrary plane it would be a bit more complicated)
for (i=0;i<3;i++) dp[i]=p[i]-dp[i];
u=p[2]/dp[2];
if (u<0.0) u=(p[2]-zFar)/dp[2]; // no intersection means "infinite" visibility
for (i=0;i<3;i++) pt[j][i]=p[i]-(u*dp[i]);
u=0.0;
}
// [draw 2D minimap]
GLint vp0[4];
GLint vp1[4]={10,10,150,150}; // minimap position and size ppixels[
double q0[2]={-1.0,-1.0 }; // minimap start point
double eu[2]={2.0/double(n),0.0}; // minimap u step
double ev[2]={0.0,2.0/double(n)}; // minimap v step
// set 2D view for minimap
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT,vp0);
glViewport(vp1[0],vp1[1],vp1[2],vp1[3]);
glColor3f(0.0,0.0,0.0); // clear background
glBegin(GL_QUADS);
for (i=0;i<2;i++) p[i]=q0[i]+(double(0)*eu[i])+(double(0)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(n)*eu[i])+(double(0)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(n)*eu[i])+(double(n)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(0)*eu[i])+(double(n)*ev[i]); glVertex2dv(p);
glEnd();
glColor3f(0.15,0.15,0.15); // grid
glBegin(GL_LINES);
for (j=0;j<=n;j++)
{
for (i=0;i<2;i++) p[i]=q0[i]+(double(j)*eu[i])+(double(0)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(j)*eu[i])+(double(n)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(0)*eu[i])+(double(j)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(n)*eu[i])+(double(j)*ev[i]); glVertex2dv(p);
}
glEnd();
glColor3f(0.5,0.5,0.5); // border of minimap
glLineWidth(2.0);
glBegin(GL_LINE_LOOP);
for (i=0;i<2;i++) p[i]=q0[i]+(double(0)*eu[i])+(double(0)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(n)*eu[i])+(double(0)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(n)*eu[i])+(double(n)*ev[i]); glVertex2dv(p);
for (i=0;i<2;i++) p[i]=q0[i]+(double(0)*eu[i])+(double(n)*ev[i]); glVertex2dv(p);
glEnd();
glLineWidth(1.0);
// 2D minimap render of the pt[]
glColor3f(0.7,0.1,0.1); // trapeze
glBegin(GL_LINE_LOOP);
for (j=0;j<4;j++)
{
// get u,v from pt[j]
for (i=0;i<3;i++) p[i]=pt[j][i]-p0[i];
for (u=0.0,i=0;i<3;i++) u+=p[i]*du[i];
for (v=0.0,i=0;i<3;i++) v+=p[i]*dv[i];
// convert to 2D position and render
for (i=0;i<2;i++) p[i]=q0[i]+(u*eu[i])+(v*ev[i]); glVertex2dv(p);
}
glEnd();
// restore 3D view
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glViewport(vp0[0],vp0[1],vp0[2],vp0[3]);
glEnable(GL_DEPTH_TEST);
}
//---------------------------------------------------------------------------
And preview:
As you can see we need just matrix*vector multiplication and pseudo inverse matrix functions for this (all others like dot,+,- are really simple and directly encoded as inline code) and both are simple enough to directly implement it in code so no need for GLM or similar lib.
Also I was too lazy to clip the 4 point polygon to minimap size so instead I used glViewport which did it for me.
Here Win32 BDS2006 VCL/C++/OpenGL1.0 Demo:
Demo Source+Binary
Just select slow download and enter the validation code from image. It does not use any 3th party libs other than GL,GLU. The camera is static so just add keyboard/mouse events to your liking. If you want to port this to your environment just mimic the events behavior and ignore the VCL stuff.
The OpenGL init is done based on this:
simple complete GL+VAO/VBO+GLSL+shaders example in C++
I just removed the GLEW,GLSL and VAO stuff from it.
My application is a vector drawing application. It works with OpenGL. I will be modifying it to instead use the Cairo 2D graphics library. The issue is with zooming. With openGL camera and scale factor sort of work like this:
float scalediv = Current_Scene().camera.ScaleFactor / 2.0f;
float cameraX = GetCameraX();
float cameraY = GetCameraY();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float left = cameraX - ((float)controls.MainGlFrame.Dimensions.x) * scalediv;
float right = cameraX + ((float)controls.MainGlFrame.Dimensions.x) * scalediv;
float bottom = cameraY - ((float)controls.MainGlFrame.Dimensions.y) * scalediv;
float top = cameraY + ((float)controls.MainGlFrame.Dimensions.y) * scalediv;
glOrtho(left,
right,
bottom,
top,
-0.01f,0.01f);
// Set the model matrix as the current matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
hdc = BeginPaint(controls.MainGlContext.mhWnd,&ps);
Mouse position is obtained like this:
POINT _mouse = controls.MainGlFrame.GetMousePos();
vector2f mouse = functions.ScreenToWorld(_mouse.x,_mouse.y,GetCameraX(),GetCameraY(),
Current_Scene().camera.ScaleFactor,
controls.MainGlFrame.Dimensions.x,
controls.MainGlFrame.Dimensions.y );
vector2f CGlEngineFunctions::ScreenToWorld(int x, int y, float camx, float camy, float scale, int width, int height)
{
// Move the given point to the origin, multiply by the zoom factor and
// add the model coordinates of the center point (camera position)
vector2f p;
p.x = (float)(x - width / 2.0f) * scale +
camx;
p.y = -(float)(y - height / 2.0f) * scale +
camy;
return p;
}
From there I draw the VBO's of triangles. This allows me to pan and zoom in. Given that Cairo only can draw based on coordinates, how can I make it so that a vertex is properly scaled and panned without using transformations. Basically GlOrtho sets the viewport usually but I dont think I could do this with Cairo.
Well GlOrtho is able to change the viewport matrix instead of modifying the verticies but how could I instead modify the verticies to get the same result?
Thanks
*Given vertex P, which was obtained from ScreenToWorld, how could I modify it so that it is scaled and panned accordng to the camera and scale factor? Because usually OpenGL would essentially do this
I think Cairo can do what you want ... see http://cairographics.org/matrix_transform/ . Does that solve your problem, and if not, why ?
I want to know how to draw a spiral.
I wrote this code:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT);
GLfloat x,y,z = -50,angle;
glBegin(GL_POINTS);
for(angle = 0; angle < 360; angle += 1)
{
x = 50 * cos(angle);
y = 50 * sin(angle);
glVertex3f(x,y,z);
z+=1;
}
glEnd();
glutSwapBuffers();
}
If I don't include the z terms I get a perfect circle but when I include z, then I get 3 dots that's it. What might have happened?
I set the viewport using glviewport(0,0,w,h)
To include z should i do anything to set viewport in z direction?
You see points because you are drawing points with glBegin(GL_POINTS).
Try replacing it by glBegin(GL_LINE_STRIP).
NOTE: when you saw the circle you also drew only points, but drawn close enough to appear as a connected circle.
Also, you may have not setup the depth buffer to accept values in the range z = [-50, 310] that you use. These arguments should be provided as zNear and zFar clipping planes in your gluPerspective, glOrtho() or glFrustum() call.
NOTE: this would explain why with z value you only see a few points: the other points are clipped because they are outside the z-buffer range.
UPDATE AFTER YOU HAVE SHOWN YOUR CODE:
glOrtho(-100*aspectratio,100*aspectratio,-100,100,1,-1); would only allow z-values in the [-1, 1] range, which is why only the three points with z = -1, z = 0 and z = 1 will be drawn (thus 3 points).
Finally, you're probably viewing the spiral from the top, looking directly in the direction of the rotation axis. If you are not using a perspective projection (but an isometric one), the spiral will still show up as a circle. You might want to change your view with gluLookAt().
EXAMPLE OF SETTING UP PERSPECTIVE
The following code is taken from the excellent OpenGL tutorials by NeHe:
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
Then, in your draw loop would look something like this:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity();
glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd();
Of course, you should alter this example code your needs.
catchmeifyoutry provides a perfectly capable method, but will not draw a spatially accurate 3D spiral, as any render call using a GL_LINE primitive type will rasterize to fixed pixel width. This means that as you change your perspective / view, the lines will not change width. In order to accomplish this, use a geometry shader in combination with GL_LINE_STRIP_ADJACENCY to create 3D geometry that can be rasterized like any other 3D geometry. (This does require that you use the post fixed-function pipeline however)
I recommended you to try catchmeifyoutry's method first as it will be much simpler. If you are not satisfied, try the method I described. You can use the following post as guidance:
http://prideout.net/blog/?tag=opengl-tron
Here is my Spiral function in C. The points are saved into a list which can be easily drawn by OpenGL (e.g. connect adjacent points in list with GL_LINES).
cx,cy ... spiral centre x and y coordinates
r ... max spiral radius
num_segments ... number of segments the spiral will have
SOME_LIST* UniformSpiralPoints(float cx, float cy, float r, int num_segments)
{
SOME_LIST *sl = newSomeList();
int i;
for(i = 0; i < num_segments; i++)
{
float theta = 2.0f * 3.1415926f * i / num_segments; //the current angle
float x = (r/num_segments)*i * cosf(theta); //the x component
float y = (r/num_segments)*i * sinf(theta); //the y component
//add (x + cx, y + cy) to list sl
}
return sl;
}
An example image with r = 1, num_segments = 1024:
P.S. There is difference in using cos(double) and cosf(float).
You use a float variable for a double function cos.