How to clip only intersection (not union) of clipping planes? - opengl

In OpenGL/JOGL, when using more than one clipping plane, the union of all clipping planes appears to be applied. What I want is instead the intersection of all clipping planes to be applied. Is this possible? See the below simplified 2-D example.
Edit: An example of clipping by vertex shader (see comments below).

Multi-pass:
#include <GL/glut.h>
void scene()
{
glColor3ub( 255, 0, 0 );
glBegin( GL_QUADS );
glVertex2i( -1, -1 );
glVertex2i( 1, -1 );
glVertex2i( 1, 1 );
glVertex2i( -1, 1 );
glEnd();
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable( GL_CLIP_PLANE0 );
// -y plane
GLdouble plane0[] = { -1, 0, 0, 0 };
glClipPlane( GL_CLIP_PLANE0, plane0 );
scene();
// -x plane
GLdouble plane1[] = { 0, -1, 0, 0 };
glClipPlane( GL_CLIP_PLANE0, plane1 );
scene();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "Clipping" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}

Using glClipPlane, no. Vertices are clipped if they are outside the positive halfspace of at least one plane. Once that happens, it doesn't matter what any other plane may be.
However, you can get this effect (or almost any other effect) by writing appropriate values to gl_ClipDistance in a vertex shader.
Any portion where the interpolated value that you write out is less than 0.0 ("negative halfspace") will be clipped, and you can write any value you like, e.g. the squared distance to a point, or the sum of distances to two planes, or anything else you calculate.

Related

Moving a lot of Shapes in Opengl

In this post the rectangle moved via mouse. I want to add a triangle and move like rectangle via mouse.
The triangle function like this:
void drawTriangle(float x,float y,float size){
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
Rectangle and triangle moved together. But I want to move it different. So what is my wrong?
You'll have to maintain an array of Shape objects and test each one for mouse collisions, as well as keep track of which Shape you're dragging:
#include <GL/glut.h>
#include <vector>
using namespace std;
struct Shape
{
float mX, mY;
float mSize;
bool mIsRectangle;
bool PointInside( const float x, const float y ) const
{
return
mX - mSize <= x && x <= mX + mSize
&&
mY - mSize <= y && y <= mY + mSize;
}
};
vector< Shape > objects;
Shape* dragging = NULL;
void mouse( int button, int state, int x, int y )
{
if( GLUT_DOWN == state )
{
dragging = NULL;
for( Shape& obj : objects )
{
if( obj.PointInside( x, y ) )
{
dragging = &obj;
glutPostRedisplay();
break;
}
}
}
else
{
dragging = NULL;
}
}
void motion( int x, int y )
{
if( dragging )
{
dragging->mX = x;
dragging->mY = y;
glutPostRedisplay();
}
}
void drawRect( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_QUADS );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, -1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glVertex2f( -1, 1 );
glEnd();
glPopMatrix();
}
void drawTriangle( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH );
const double h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
for( const Shape& obj : objects )
{
if( obj.mIsRectangle )
drawRect( obj.mX, obj.mY, obj.mSize );
else
drawTriangle( obj.mX, obj.mY, obj.mSize );
}
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
Shape temp;
temp.mSize = 50;
temp.mX = temp.mY = 100;
temp.mIsRectangle = true;
objects.push_back( temp );
temp.mX = temp.mY = 200;
temp.mIsRectangle = false;
objects.push_back( temp );
glutMainLoop();
return 0;
}

opengl rubberbanded box not showing

I'm trying to draw a selection box over an image drawn using glDrawPixels, but I cannot get it to show. In order to represent the coordinates of the box, I have 4 global integers that I update on mouse actions (the first 2 on click, the others when the mouse is dragged), which I then use in the drawing function. I'm sure that the drawing function is called when the mouse gets dragged, and that the four values at least get updated, since I tried printing them every time the drawing function gets called.
The OpenGL calls I have in the main are:
glutInit(&argc, argv);
glutInitWindowSize(WINDOW_DIM, WINDOW_DIM);
glutInitWindowPosition(0, 0);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutCreateWindow("Window");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glClearColor(0.0, 0.0, 0.0, 1.0);
glDisable(GL_DEPTH_TEST);
glutMainLoop();
and my display function:
void display()
{
printf("calling display\n");
for(unsigned int i=0; i<WINDOW_DIM*WINDOW_DIM; ++i)
{
pixels[i]=colors[img[i]];
}
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(WINDOW_DIM, WINDOW_DIM, GL_RGB, GL_FLOAT, (float*)pixels);
glutSwapBuffers();
if(upd_xmin!=0 || upd_ymin!=0 || upd_xmax!=0 || upd_ymax!=0)
{
glDrawBuffer(GL_FRONT);
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
printf("drawing selection\n");
printf("coords %d %d %d %d\n", upd_xmin, upd_ymin, upd_xmax, upd_ymax);
glColor3f(1.0, 1.0, 1.0);
glLineWidth(3.0);
glBegin(GL_LINE_LOOP);
glVertex2i(upd_xmin, upd_ymin);
glVertex2i(upd_xmin, upd_ymax);
glVertex2i(upd_xmax, upd_ymax);
glVertex2i(upd_xmax, upd_ymin);
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
glDrawBuffer(GL_BACK);
}
}
As I said, I don't think the problem is with the mouse and motion function, seeing how the coordinates of the box (the upd_x and upd_y variables in the code above) get updated when there's a mouse event, but if needed I can post those as well.
Don't swap the buffers in the middle. Just draw the selection box on the back-buffer like everything else:
#include <GL/glut.h>
int StartX = -1;
int StartY = -1;
int EndX = -1;
int EndY = -1;
void mouse( int button, int state, int x, int y )
{
if( button == GLUT_LEFT && state == GLUT_DOWN )
{
StartX = x;
StartY = y;
}
if( button == GLUT_LEFT && state == GLUT_UP )
{
StartX = -1;
StartY = -1;
EndX = -1;
EndY = -1;
}
}
void motion( int x, int y )
{
EndX = x;
EndY = y;
glutPostRedisplay();
}
void display()
{
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glBegin( GL_TRIANGLES );
glColor3ub( 255, 0, 0 );
glVertex2i( -1, -1 );
glColor3ub( 0, 255, 0 );
glVertex2i( 1, -1 );
glColor3ub( 0, 0, 255 );
glVertex2i( 0, 1 );
glEnd();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
if( StartX > 0 && StartY > 0 && EndX > 0 && EndY > 0 )
{
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
glColor3f(1.0, 1.0, 1.0);
glLineWidth(3.0);
glBegin(GL_LINE_LOOP);
glVertex2i(StartX, StartY);
glVertex2i(EndX, StartY);
glVertex2i(EndX, EndY);
glVertex2i(StartX, EndY);
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
}
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
glutMainLoop();
return 0;
}
Since you weren't specifying them I added projection and modelview matrices.
I believe the problem lies here:
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(WINDOW_DIM, WINDOW_DIM, GL_RGB, GL_FLOAT, (float*)pixels);
glutSwapBuffers();
rest of drawing
Your render call should look like:
clear
render
swap buffers
Where render is all of your draw calls (including glDrawPixels).
Also, glDrawPixels was removed in OpenGL 3.2. Unless you absolutely need to use that particular method, why not use an orthographic projection to draw GUI elements (which the selection box can be though of as)?
Edit: Also, be aware that if you make draw calls after glDrawPixels, those may overwrite what you drew with glDrawPixels.

Turning picture upside down when using glDrawPixels

I'm getting really strange results when using glDrawPixels() in combination with glRasterPos2*() and glPixelZoom(). I've got a picture and I'd like to show it like old framebuffers used to, i.e. (0,0) being in the topleft corner. Here's the code:
void GLWidget::resizeGL( int w, int h )
{
glViewport( 0, 0, w, h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, w, 0, h, -1, 1 );
}
void GLWidget::paintGL()
{
for( int i = 0; i < SCREEN_WIDTH; ++i )
{
displayBitmap[i] = 0xf81f;
}
for( int i = 239 * SCREEN_WIDTH; i < 239 * SCREEN_WIDTH + SCREEN_WIDTH; ++i )
{
displayBitmap[i] = 0xf800;
}
//glRasterPos2f( 0, SCREEN_HEIGHT - 0.1 );
glRasterPos2i( 0, SCREEN_HEIGHT - 1 );
glPixelZoom( 1, -1 );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glDrawPixels( SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, displayBitmap );
}
If executed as it is now, I'm getting the violet line at (0,1), i.e. one black line, then the violet line and then, in the invisible bottom area, is the red line.
OK, so I change
glRasterPos2i( 0, SCREEN_HEIGHT - 1 );
to
glRasterPos2i( 0, SCREEN_HEIGHT );
Nope, output is corrupted. Strangely, if I change it to:
glRasterPos2f( 0, SCREEN_HEIGHT - 0.1 );
it works, both lines are drawn, in the correct order (SCREEN_HEIGHT and SCREEN_HEIGHT - 1.0 lead to the same result as in the integer version).
What I'm doing wrong here? SCREEN_WIDTH = 320, SCREEN_HEIGHT = 240.
This works for me:
void display() {
unsigned char *pixels=captureScreenRegion(0,0,window_width,window_height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRasterPos2f(-1,1);
glPixelZoom( 1, -1 );
glDrawPixels(window_width,window_height,GL_RGB,GL_BYTE,pixels);
free(pixels);
glutSwapBuffers();
}
glDrawPixels is only poorly supported on consumer grade hardware. And in newer OpenGL versions it has been removed entirely. Instead of spending time trying to get this to work, just load your image into a texture and draw a textured quad with a trivial shader with it.
Trust me, messing around with glDrawPixels is not worth the effort.
I meet the same problem as you do. I solved it this way:
void VideoRenderWidget::resizeGL(int w, int h)
{
glViewport( 0, 0, w, h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, w, 0, h, 0.1, 1 );
glPixelZoom( 1, -1 );
glRasterPos3f(0, h - 1, -0.3);
}
void VideoRenderWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawPixels(704, 576, GL_RGB, GL_UNSIGNED_BYTE, buffer_.data_);
}
This worked for me.. I am still developing this.. here 704 is video width and 576 is height.

GLUT: Wrong Mouse Coordinates?

Using SCREEN_WIDTH = 1200, and SCREEN_HEIGHT = 800.
First, I draw a box to the screen at (x = 0, y = 0, w = 40, h = 40);
Then I use the handleMouse Function to return the x and y coordinates of where the mouse is clicked.
The problem is, when the program starts in non-Maximized windowed mode, when I click on (What appears to be) the very bottom right corner of the box the coordinates returned are x = 40, y = 32. When I think it should be returning x = 40, y = 40.
I don't know whether the problem is if its not being drawn right, or the functions is returning the wrong x/y.
I believe I understand how openGL rendering, transformation and glOrth work, but I could be completely wrong. I have seen a few suggestions online saying that the Windows Decor(Using windows 7) can cause this problem, but have done very little explaining and provided no solution.
This is my entire source code. I have stripped off everything from my game down to the basics, and the problem still persists :( . I added two pictures so people could see my problem. In NON-MAXIMIZED WINDOW(the top picture), when clicking the bottom-right corner, the coordinates returned are 41,32; The y coordinate is smaller than it should be. And in the MAXIMIZED WINDOW(the bottom picture), when clicking the same corner, It returns the correct coordinates 40, 40. These results occur for both my original source code and genpfault's suggested code.
//Turns out I can't post Pictures :(, links instead.
non-Maximized Windowed!
Maximized Windowed!
main.cpp
int main( int argc, char* args[] )
{
//Initialize FreeGLUT
glutInit( &argc, args );
//Create OpenGL 2.1 context
glutInitContextVersion( 2, 1 );
//Create Double Buffered Window
glutInitDisplayMode( GLUT_DOUBLE );
glutInitWindowSize( SCREEN_WIDTH, SCREEN_HEIGHT );
glutCreateWindow( "OpenGL" );
//Do post window/context creation initialization
if( !initGL() )
{
printf( "Unable to initialize graphics library!\n" );
return 1;
}
//initGame();
glutMouseFunc(handleMouse);
glutDisplayFunc( render );
glutMainLoop();
return 0;
}
Functions.h
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
bool initGL();
void render();
void handleMouse(int button, int state, int x, int y);
#endif
Functions.cpp
bool initGL()
{
//Initialize clear color
glClearColor( 0.f, 0.f, 0.f, 1.f );
//Check for error
GLenum error = glGetError();
if( error != GL_NO_ERROR )
{
//cout <<"Error initializing OpenGL! " << gluErrorString( error ) << endl;
return false;
}
return true;
}
void render()
{
//Clear color buffer
glClear( GL_COLOR_BUFFER_BIT );
glColor3f(1.f,1.f,1.f);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBegin(GL_QUADS);
glVertex2f(0,0);
glVertex2f(0, 41);
glVertex2f(41, 41);
glVertex2f(41, 0);
glEnd();
glutSwapBuffers();
}
void handleMouse(int button, int state, int x, int y)
{
std::cout << x << '\t' << y << std::endl;
}
constants.h
const int SCREEN_WIDTH = 1200;
const int SCREEN_HEIGHT = 800;
This works fine for me on Windows 7 on Aero and Classic:
#include <GL/glut.h>
#include <iostream>
void render()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho(0, w, h, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3ub( 255, 255, 255 );
glBegin(GL_QUADS);
glVertex2f(0,0);
glVertex2f(41, 0);
glVertex2f(41, 41);
glVertex2f(0, 41);
glEnd();
glutSwapBuffers();
}
void handleMouse(int button, int state, int x, int y)
{
std::cout << x << '\t' << y << std::endl;
}
int main( int argc, char* args[] )
{
glutInit( &argc, args );
glutInitDisplayMode( GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "OpenGL" );
glutMouseFunc(handleMouse);
glutDisplayFunc( render );
glutMainLoop();
return 0;
}
Most notably I added the runtime glutGet() window size queries to render().
Try moving the quad away from the edge of the display because when I tryed to do something like that the edge of the screen was very odd
glBegin(GL_QUADS);
glVertex2f(20,20);
glVertex2f(20, 61);
glVertex2f(61, 61);
glVertex2f(61, 20);
glEnd();

SDL OpenGL C++ problem

I'm trying to make a simple game of pong using SDL and OpenGL in C++ and I'm having trouble displaying any sort of OpenGL image onto the screen and was wondering if anybody could help:
Initialization:
void init_everything()
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_SetVideoMode( width_of_screen, height_of_screen, bpp_of_screen, SDL_OPENGL );
glClearColor( 0, 0, 0, 0 );
// Sets the projection
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, width_of_screen, height_of_screen, 0, 1, -1 );
// initalises the modelview matrix
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
SDL_WM_SetCaption( "Pong - By Michael Clover", NULL );
}
After this I call the class function:
void paddle::show()
{
//Move to offset
glTranslatef( x, y, 0 );
//Start quad
glBegin( GL_QUADS );
//Set color to white
glColor4f( 1.0, 1.0, 1.0, 1.0 );
//Draw square
glVertex3f( 0, 0, 0 );
glVertex3f( paddle_width, 0, 0 );
glVertex3f( paddle_width, paddle_height, 0 );
glVertex3f( 0, paddle_height, 0 );
//End quad
glEnd();
//Reset
glLoadIdentity();
}
I then put this in my main function:
int main( int argc, char **argv )
{
bool quit = false;
init_everything();
paddle playerpaddle;
while (quit == false )
{
while( SDL_PollEvent( &event ) )
{
playerpaddle.handle_input();
if (event.type == SDL_QUIT)
{
quit = true;
}
}
playerpaddle.move();
glClear( GL_COLOR_BUFFER_BIT );
playerpaddle.show();
SDL_GL_SwapBuffers();
}
clean_up();
return 0;
}
All I get is a constant black background screen that I set within a 640 by 480px SDL screen.
Sorry for the huge amount of text and I would be extremely grateful for any insight on what the problem could be here, I'm guessing I'm making a silly mistake somewhere.
I think glOrtho might be set up wrong. The last 2 parameters are near and far clipping planes. Your near plane should be less than zero if you don't want to clip your paddle. And your far plane should be greater than zero. So try this:
glOrtho( 0, width_of_screen, height_of_screen, 0, -1, 1 );
Just 2 things to check now that you've ruled out errors:
Try removing the glTranslatef call. It may be too far off for you to see the scene.
Are you creating your vertices in a clockwise order? I can't tell by the variables you used, but if paddle_height is > 0 or paddle_width < 0, it's not going to be clockwise (which it needs to be).
Try this for your projection instead (if you want 0,0,0 at your center).
double range = 4.0; // Set this to whatever you want for the range of the display.
double ratio = double(displayWidth) / double(displayHeight);
glOrtho(-range* ratio, range* ratio, -range, range, -1.0, 1.0);
Temporarily try to render a square from -1.0,-1.0 to 1.0,1.0 to see if your display is working.