I'm using 3d mode to render my 2d game, because the camera rotation and zooming in/out is much easier than with 2d mode.
Now i have ran into a problem i cant seem to think how to fix:
How to make the 2d plane of my world to fit the screen in a way that 1 texture pixel matches 1 pixel on my screen? In other words: how do i calculate the z-position of my camera to achieve this?
My texcoords start from 0 and ends to 1, so i can see all the pixels from one tile in the GL_NEAREST texture filter mode.
My window is resizeable in a way that my tiles are always squares but the visible area expands depending on how i resize my window.
Edit: my view port is using perspective mode, not isometric. but if its not possible in perspective mode, im willing to change to isometric.
Use an orthographic projection that maps eye space units to pixels:
glViewport(0,0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -1, 1);
Update due to question update:
A texel → viewport pixel matching is possible with a perspective projection, but only under a certain constraint: The textured quad must be coplanar to the perspective frustum near/far plane.
How to do it? For glFrustum(left, right, bottom, top, near, far) with Z=near, XY eye space range [left, right]×[bottom, top] maps to NDC xy[-1, 1]² and NDC xy[-1, 1]² maps to the viewport extents. So those are all affine transformations following the law
y(x) = to_lower_bound + (x - from_lower_bound) * (to_upper_bound - to_lower_bound) / (from_upper_bound - from_lower_bound)
All you have to do it map viewport to NDC to near plane and if you're Z =/= near scale by near/Z.
Related
I have the following problem, when I zoom in on the image. I have not been able to solve it. I am currently developing in Qt with c ++. I have a question about orthogonal projection and perspective projection. I need to zoom without traversing the image. I tried to make the glViewport bigger, but it does not work for me. The xmin, xmax... are the maximum and minimum values for each axis.
void MeshViewer::resizeGL(int width, int height)
{
int side = qMin(width, height);
if ( height == 0 )
height = 1;
glViewport(((GLint)(width - side)/2.0), (GLint)((height -side)/2.0), (GLint)side, (GLint)side);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glOrtho(xmin, xmax, ymin, ymax, zmin, zmax);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
glViewport specifies the mapping of normalized device coordinates to window coordinates (pixels).
If you want that the entire geometry which is inside the clip space, is mapped to the window, then it has to be:
glViewport(0, 0, width, height)
What the window displays is a frustum, defined by six planes. Normally, these planes are parallel, as in a cube. Anything that lies outside the frustum is not displayed.
"Zoom" may be interpreted, in a generic way, as "see bigger, nearer, more detail".
There are several ways of achieve the zoom effect:
Scale the objects. This works, the flaw is that objects (or parts of them) may lie before the near plane or behind the far plane of the frustum.
Move the camera towards the object. Same matter with near/far planes. Also, take care of moving through the model, you can set a "barrier" (perhaps a box) to prevent the camera moving too deep.
For an orthogonal projection, set left/right/top/bottom planes nearer to the object. This makes the frustum smaller, thus it's normal that some objects get clipped.
For a perspective projection you can do the same trick as with orthogonal. This trick is just to reduce the FOV (field of view) angle. If objects are too far, the perspective effect may be less obvious.
I understand i need to render only 1x1 or 3x3 pixel part of the screen where the mouse is, with object id's as colors and then get id from the color.
I have implemented ray-cast picking with spheres and i am guessing it has something to do with making camera look in direction of the mouse ray?
How do i render the correct few pixels?
Edit:
setting camera in direction of mouse ray works, but if i make the viewport smaller the picture scales but what (i think) i need is for it to be cropped rather than scaled. How would i achieve this?
The easiest solution is to use the scissor test. It allows you to render only pixels within a specified rectangular sub-region of your window.
For example, to limit your rendering to 3x3 pixels centered at pixel (x, y):
glScissor(x - 1, y - 1, 3, 3);
glEnable(GL_SCISSOR_TEST);
glDraw...(...);
glDisable(GL_SCISSOR_TEST);
Note that the origin of the coordinate system is at the bottom left of the window, while most window systems will give you mouse coordinates in a coordinate system that has its origin at the top left. If that's the case on your system, you will have to invert the y-coordinate by subtracting it from windowHeight - 1.
I'm working on a tile-based 2D OpenGL game (top down, 2D Zelda style), and I'm using an orthographic projection. I'd like to make this game both windowed and fullscreen compatible.
Am I better off creating scaling 2D drawing functions so that tile sizes can be scaled up when they're drawn in fullscreen mode, or should I just design the game fully around windowed mode and then scale up the ENTIRE drawing area whenever a player is in fullscreen mode?
In the end, I'm hoping to maintain the best looking texture quality when my tiles are re-scaled.
UPDATE/CLARIFICATION: Here's my concern (which may or may not even be a real problem): If I draw the entire windowed-view-sized canvas area and then scale it up, am I potentially scaling down originally 128x128 px textures to 64x64 px windowed-sized textures and then re-scaling them up again to 80x80 when I scale the entire game area up for a full screen view?
Other background info: I'm making this game using Java/LWJGL and I'm drawing with OpenGL 1.1 functions.
Dont scale tiles because your fullscreen window is larger than the normal one, but play with the projection matrix.
The window is getting larger? Enlarge the parameters used for constructing the projection matrix.
If you want to mantain proportional the tile size respect the window size, don't change projection matrix depending on window size!
The key is, if you haven't catched yet, the projectiona matrix: thanks to it, vertices are projected onto the viewport, indeed vertices are "scaled", letting you to choose appropriate unit system without worring about scaling.
In few words, the orthographic projection is specified from 4 parameters: left, right, bottom and top. Those parameters are nothing but the XY coordinates of the vertex projected onto the window screen boundaries (really the viewport).
Let do some concrete example.
Example 1
Window size: 400x300
OpenGL vertex position (2D): 25x25
Orthographic projection matrix:
- Left= 0
- Right= 400
- Bottom= 0
- Top= 300
Model view matrix set to identity
--> Point will be drawn at 25x25 in window coordinates
Example 2
Window size: 800x600 (doubled w.r.t example 1)
OpenGL vertex position (2D): 25x25
Orthographic projection matrix:
- Left= 0
- Right= 400
- Bottom= 0
- Top= 300
Model view matrix set to identity
--> Point will be drawn at 50x50 in window coordinates. It is doubled because the orthographic projection haven't changed.
Example 3
Let say I want to project the vertex in example 1 even if the aspect ratio of the window changes. Previous windows were 4:3. The window in this example is 16:9: it is larger! The trick here is to force the ratio between (right - left) and (top - bottom)
Window size: 1600x900 (doubled w.r.t example 1)
OpenGL vertex position (2D): 25x25
Orthographic projection matrix:
Left= 0
Right= 533 (300 * 16 / 9)
Bottom= 0
Top= 300
Model view matrix set to identity
--> Point will be drawn at 25x25 (instead of 33.3x25, if we were using the projection matrix of the example 1) in window coordinates.
Well the thing is, that I wan't to picture mazes with a different width and height. I'm drawing them in units and my question is, how can I get the plane viewable dimensions in units that I would know how deep inside the screen I would have to draw my maze in order it would be fully seeable. For perspective view I use "::gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 100.0f);"
For example how I get the near plane dimensions(width and height) in OpenGL units or the far plane or any plane between those planes. If I want to picture something entirely seeable I need to know the plane dimensions in OpenGL units or is there another way?
A bit of trigonometry will tell you that: h_near = 2*near*tan(fovy/2) and the same for far: h_far = 2*far*tan(fovy/2)
Then, the ratio will give you the width.
For the "proof", just consider the right-angled triangle formed by the line of view, the vertical of the plane of rendering and back. The length of the line of view is near or far (depending), the angle at the eye position is fovy/2 (i.e. half the view angle) and the vertical on the plane is h_near/2 or h_far/2, as we only get half-way to the plane. Then, the tangent of the angle on a right-angled triangle is equal to the far-side divided by the near-side ...
Short Version of the question:
I will put a quad. I know the width and height of the screen in window coordinates, i know the Z-coordinates of the quad in 3D. I know the FOVY, I know the aspect. The quad will be put along Z-axis, My camera doesn't move (placed at 0, 0, 0). I want to find out the width and height of the quad IN 3D COORDINATES that will fit exactly onto my screen.
Long Version of the question:
I would like to put a quad along the Z-axis at the specified offset Z, I would like to find out the width and height of the quad that will exactly fill the entire screen.
I used to have a post on gamedev.net that uses a formula similar to the following:
*dist = Z * tan ( FOV / 2 )*
Now I can never find the post! Though it's similar, it is still different, because I remembered in that working formula, they do make use of screenWidth and screenHeight, which are the width and height of the screen in window coordinates.
I am not really familiar with concepts like frustum, fov and aspect so that's why I can't work out the formula on my own. Besides, I am sure I don't need gluUnproject (I tried it, but the results are way off). It's not some gl calls, it's just a math formula that can find out the width and height in 3D space that can fill the entire screen, IF Z offset, width in window coordinates, and height in window coordinates, are known.
Assuming the FOV is measured in Y-Z plane, then:
Height = Z * tan(fov/2)
width = height * aspect_ratio