I made a window sized 800x600. I called
gluOrtho2D(-400,400,-300,300);
glViewport(400,300,400,300);
and I drew a line from (-100,-100) to (100,100). I think I should see a line from (0,0) to (100,100), but I am getting the whole line. Why is this?
In theory, glViewport doesn't cause any clipping (see section 10). Normally, all drawing is clipped to the window. Since you have asked OpenGL to draw into a region of your window, you will need to also tell OpenGL to clip coordinates outside this viewport. For that, you will need glScissor. However, some implementations do clip their drawing to the viewport (see my comment for details).
In addition, your math is wrong. Your projection matrix is 800 units wide by 600 units tall, centered at (0, 0). This is then mapped to a portion of the window that is 400 pixels wide by 300 pixels tall, in the upper-right corner of the window.
If you draw a line from (-100, -100) to (100, 100), it will extend across only a small part of your viewing frustrum. The frustrum is sized to fit in the viewport.
In the image, the blue box is the window, and the red box represents the viewport. The black line should be the line that you drew.
An image describing what the paragraph says. http://img696.imageshack.us/img696/6541/opengl.png
Hope that helps!
glViewport describes the area of your window which will be drawn by OpenGL.
glOrtho or gluOrtho2D define a unit system (OpenGL units) which fit into that (via glViewport defined) area.
So your line will be drawn within the Viewport from -100,-100 to 100,100
Related
I was doing a test program with direct2d to show lines, however I noticed a little detail and that is that when I tell direct2d to draw a dotted line (100,200) and (500,200), direct2d really isn't drawing the beginning of the line at the point (100,200), but it draws it one pixel less, that is, it coordinates at the coordinate (100,99). Does anyone know why this is? I checked this detail using direct2d without antialiasing mode and showing in the debug output the mouse coordinates.
This is caused by Direct2D's own design.
To be precise, the coordinates of the line are from (99.5, 199.5) - (500.5, 200.5).
And #Rick Brewster's answer has explained these.
When you give it a pixel coordinate such as (100, 120), that refers to
the top and left corner of the pixel element that spans from pixel
coordinates (100, 120) to (101, 121) (top/left are inclusive,
right/bottom are exclusive). Since it's a straight horizontal line you
are effectively getting a filled rectangle from (99.5, 119.5) -
(300.5, 120.5).
So if you want to draw a line from that covers the pixels (100, 200) to
(500, 200), you can use aliased rendering or use half-pixel offsets.
I have a small custom ray tracer that I am integrating in an application. There is a resizable OpenGL window that represents the camera into the scene. I have a perspective matrix that adjusts the overall aspect ratio when the window resizes (basic setup).
Now I would like to draw a transparent rectangle over the window representing the width x height of the render so a user knows exactly what will be rendered. How could this be done? How can I place the rectangle accurately? The user can enter different output resolutions for the ray tracer.
If I understand well your problem, I think that your overlay represents the new "screen" in your perspective frustum.
Redefine then a perspective matrix for the render, in which the overlay 4 corners define the "near" projection plane.
I have a viewport that is half of the screen size/framebuffer.
x, y, w, h = 0, 0, 512, 512
And my scissor region is the full framebuffer
x, y, w, h = 0, 0, 0 1024, 512
I am drawing a line, that is far outside of the viewport, from left to right. I am expecting the line to be drawn only inside the viewport. I have tested this on three different graphic cards, and on two of them, I get the result I am I expecting. However on the third one, the line is drawn outside the viewport, but inside the scissor region.
Which one of the results is correct here? As far as I understand it, the lines' two vertices should be moved to outer viewport positions. It should not be drawn outside of it.
If you read pitfall nr 10 on this site:
https://www.opengl.org/archives/resources/features/KilgardTechniques/oglpitfall/
They are talking about drawing outside the viewport, but that is just some special cases, for example where you have a really thick line, my line width is 1
EDIT: After a discussion in the KhronosGroup:
From the spec Vulkan 1.0.68:
If either of a line segment’s vertices lie outside of the clip volume,
the line segment may be clipped, with new vertex coordinates computed
for each vertex that lies outside the clip volume. A clipped line
segment endpoint lies on both the original line segment and the
boundary of the clip volume.
Nvidia:
We intentionally made this change for maintenance2, to allow for
pop-free points and lines. Point clipping behavior is queriable but
line clipping behavior is not, though I believe the "preferred"
behavior for lines is to be pop-free. We changed the NVIDIA driver
last year from tight clipping to pop-free, and even changed CTS tests
to allow this new behavior. So this is all working as designed.
Old answer:
The viewport defines a transformation from normalized device coordinates to window coordinates. The viewport transformation does not do any clipping.
However, the clipping does happen before NDC space, the view frustum clipping does guarantee that no vertex can fall outside the viewport. And if you are using orthogonal projection, clip space and NDC space are the same. So everything outside [-1,1] will be clipped. And if you are not doing any of the special cases the opengl link talks about the vertices should be clipped.
If two of your graphics cards draws inside the viewport and one outside, it's probably a driver bug. If you are using Vulkan, which is fairly new, that is most likely the case.
Edit: My answer below is technically correct but not useful. The viewport transform itself doesn't define a clip volume or scissor. But because of clipping to the view frustum ([-w,+w] for x and y, [0,+w] for z), all the (x,y) values entering the viewport transform will be in [-1,1], and will not be transformed to fall outside of the rectangle that defined the viewport.
Like in GL, the viewport only defines a transform from normalized device coordinates to framebuffer coordinates. The transform is based on the width/height/depth/origin of the viewport volume, but that volume doesn't define a clipping volume. The math is described in section 23.5 Controlling the Viewport.
In Vulkan you can also specify a scissor rectangle in framebuffer coordinates for each viewport, in VkPipelineViewportStateCreateInfo:: pScissors or vkCmdSetScissor. Pixels outside this rectangle are dropped. But you have to set the scissor rectangle yourself, and it doesn't have to match the viewport volume.
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.
How to clip rendering in OpenGL (simple rectangle area)?
Please post a C++ example.
What you probably need is OpenGL's scissor mechanism.
It clips rendering of pixels that do not fall into a rectangle defined by x, y, width and height parameters.
Note also that this OpenGL state when enabled, affects glClear command by restricting the area cleared.
If you only want to display a specific rectangle, you need a combination of something like glFrustrum or glOrtho along with glViewPort. It's actually glViewPort that sets the clipping rectangle. glFrustrum, glOrtho (gluPerspective, etc.) then map some set of real coordinates to that rectangle. Typically you hardly notice the glViewPort, because it's normally set to the entire area of whatever window you're using, and what you change is the mapping to get different views in the window.
If you just adjust glFrustum (for example) by itself, the display area on the screen will stay the same, and you'll just change the mapping so you'll still fill the entire window area, and basically just move the virtual camera around, so you zoom in or out (etc.) on the "world" being displayed. Conversely, if you just adjust glViewPort, you'll display exactly the same data, but into a smaller rectangle.
To "clip" the data to the smaller rectangle, you need to adjust both at once, in more or less the "opposite" directions so as your view-port rectangle gets smaller, you zoom in your view frustum to compensate.