Hey everybody,

I was just wondering, how do you create Lens Distortion in OpenGL? As in, the rendered image looks bloated or sucked in when you implement it.
I would typically want it in a simple format that works nicely and doesn't eat up too much CPU.

As an extra, how about a spiral distortion? (I've seen it once when I was playing C&C Yuri's Revenge)

Thanks in advance.

Recommended Answers

All 13 Replies

Basically, the examples you gave are all part of the same family of tricks: non-linear projections. As you know, the projection matrix takes objects (vertices) from the 3D world (cartesian) space to a projective space (the frustum, with 2D screen coordinates and depth). But the projection matrix is a linear transformation. This greatly limits what it can accomplish, basically, no "roundish" distortions are possible with it.

So, to create non-linear projections, there might be special-purpose extensions to do this but I don't know any. How most people do it is you substitute the so-called "fixed rendering pipeline" with a pair of vertex and fragment shader. These are simple programs (usually only a few lines long) that can be send to and compiled on the graphics card (via simple OpenGL commands) and used by the graphics card instead of the default rendering pipeline you find in basic OpenGL rendering (with little to no special effects). This is a very vast topic and I am far from being an expert, I suggest to read up on it. A lens effect is probably fairly easy to make and I would suspect you can find open-source shader programs that do that, it's no big deal.

Now, some effects will not be possible just using shaders, you will need multiple rendering passes, in so-called render-to-texture techniques. As with your example of the spiral distortion, this, as far as I can tell, cannot be done well only with a sophisticated shader (because of some inherent limitations of shaders). Basically, what people do is render the scene on a texture (instead of the screen), and then, use shader programs to distort the texture as it is applied to a surface. Again, I'm no expert and I can tell from the things they do in some computer games that they know many tricks that I don't, but these two are already pretty powerful, if you have enough imagination and can grasp the hairy mathematics of it all.

Alright, I've coded the example at NeHe Productions (awesome site!) and I have got some wonderful results with the CG Vertex Buffer (Lesson 47). I familiarized myself with the code and I know how to make some basic transformations.

...

Now how do I make it distort light instead of objects?

I think I might have to use Fragment Shading (Pixel Shading). I'm looking into this now.

UPDATE: I went through your message once more, you already suggested to me to use "a pair of vertex and fragment shader". My bad.

Alright! I've got what I wanted. I've hacked together some functions that will help to distort the screen with sine, square, and arcsine functions with minimal difficulty.

This was an odd mixture of NeHe's lesson 36 (Radial Blur) and a link I mentioned earlier.

Here's the header:

#ifndef DISTORTION_H_INCLUDED
#define DISTORTION_H_INCLUDED

#define SIGN(x) (x < 0 ? (-1) : 1)

#define PID2 1.5707963268

GLuint EndTexture;
//Assign EndTexture to this function when initializing
GLuint EmptyTexture() {											// Create An Empty Texture
	GLuint txtnumber;											// Texture ID
	unsigned int* data;											// Stored Data

	// Create Storage Space For Texture Data (128x128x4)
	data = (unsigned int*)new GLuint[((ScreenSizeX * ScreenSizeY)* 4 * sizeof(unsigned int))];
	ZeroMemory(data,((ScreenSizeX * ScreenSizeY)* 4 * sizeof(unsigned int)));	// Clear Storage Memory

	glGenTextures(1, &txtnumber);								// Create 1 Texture
	glBindTexture(GL_TEXTURE_2D, txtnumber);					// Bind The Texture
	glTexImage2D(GL_TEXTURE_2D, 0, 4, ScreenSizeX, ScreenSizeY, 0,
		GL_RGBA, GL_UNSIGNED_BYTE, data);						// Build Texture Using Information In data
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

	delete [] data;												// Release data

	return txtnumber;											// Return The Texture ID
}

void Transform(GLfloat x, GLfloat y, GLfloat *ix, GLfloat *iy) {
    GLfloat xnew,ynew;
    GLfloat r,theta,rnew,thetanew;
    
    //r = sqrt(x*x+y*y);
    //theta = atan2(y,x);
    
    //NONE
        xnew = x;
        ynew = y;
    //SINE XY
        //xnew = sin(PID2*x);
        //ynew = sin(PID2*y);
    //SINE R
        //rnew = sin(PID2*r);
        //thetanew = theta;
        //xnew = rnew * cos(thetanew);
        //ynew = rnew * sin(thetanew);
    //SQUARE XY
        //xnew = x*x*SIGN(x);
        //ynew = y*y*SIGN(y);
    //SQUARE R
        //rnew = r*r;
        //thetanew = theta;
        //xnew = rnew * cos(thetanew);
        //ynew = rnew * sin(thetanew);
    //ASIN XY
        //xnew = asin(x) / PID2;
        //ynew = asin(y) / PID2;
    //ASIN R
        //rnew = asin(r) / PID2;
        //thetanew = theta;
        //xnew = rnew * cos(thetanew);
        //ynew = rnew * sin(thetanew);
    
    *ix = xnew;
    *iy = ynew;
}
void CreateGrid(void) {
    /*glMatrixMode(GL_PROJECTION);								// Select Projection
	glPushMatrix();												// Push The Matrix
	glLoadIdentity();											// Reset The Matrix
	glOrtho( 0, ScreenSizeX, ScreenSizeY, 0,-1, 1);				// Select Ortho Mode
	glMatrixMode(GL_MODELVIEW);									// Select Modelview Matrix
	glPushMatrix();												// Push The Matrix
	glLoadIdentity();											// Reset The Matrix*/
    
    GLfloat i, j, n = 0.05f;
    GLfloat x, y;
    
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glBindTexture(GL_TEXTURE_2D, EndTexture);
    glColor3f(aWhite);
    for (i = -1.0f; i < 1.0f; i += n) {
       glBegin(GL_TRIANGLE_STRIP);
       for (j = -1.0f; j < 1.0f; j += n) {
          Transform( i  , j  , &x, &y);
          glTexCoord2f( (x+1.0f)*0.5f, (y+1.0f)*0.5f); glVertex3f( i   , j   *0.75f, 0.0);
          Transform( i+n, j  , &x, &y);
          glTexCoord2f( (x+1.0f)*0.5f, (y+1.0f)*0.5f); glVertex3f((i+n), j   *0.75f, 0.0);
          Transform( i  , j+n, &x, &y);
          glTexCoord2f( (x+1.0f)*0.5f, (y+1.0f)*0.5f); glVertex3f( i   ,(j+n)*0.75f, 0.0);
          Transform( i+n, j+n, &x, &y);
          glTexCoord2f( (x+1.0f)*0.5f, (y+1.0f)*0.5f); glVertex3f((i+n),(j+n)*0.75f, 0.0);
       }
       glEnd();
    }
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);
	
    /*glBegin(GL_TRIANGLE_STRIP);
        glTexCoord2f( 0, 0); glVertex3f( 0          , ScreenSizeY, 0.0f);
        glTexCoord2f( 1, 0); glVertex3f( ScreenSizeX, ScreenSizeY, 0.0f);
        glTexCoord2f( 0, 1); glVertex3f( 0          , 0          , 0.0f);
        glTexCoord2f( 1, 1); glVertex3f( ScreenSizeX, 0          , 0.0f);
    glEnd();*/
    
    /*glMatrixMode( GL_PROJECTION );								// Select Projection
	glPopMatrix();												// Pop The Matrix
	glMatrixMode( GL_MODELVIEW );								// Select Modelview
	glPopMatrix();												// Pop The Matrix*/
}

void DrawGLScene(void);
void RenderToTexture() {						// Renders To A Texture
    DrawGLScene();
    
	glBindTexture(GL_TEXTURE_2D, EndTexture);
	// Copy Our ViewPort
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, ScreenSizeX, ScreenSizeY, 0);
    
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And Depth Buffer
}

#endif

For this to take permanent effect, just replace DrawGLScene() with RenderToTexture() and CreateGrid().

There are complications however.
1) The rendered scene will not fill 100% of the window.
2) This code must affect the whole view, not just a portion.

These complications are because I wasn't able to change the code to an orthographic projection. The screen somehow ended up blank.

Yeah, so basically, you did the render-to-texture technique that I mentioned in my previous post (which is what you need for lens distortion, now that I think about it). Nicely done!

>>1) The rendered scene will not fill 100% of the window.
Since the scene is distorted, it will not fit inside a rectangular screen (there might be slightly more complex functions that can match the square boundary). I think the easiest is probably to scale the grid (glScalef()) such that it is just big enough to not leave any black spots around. Also, you don't have to have a black background, if you use another color (glClearColor()) or background image that replaces the black spots by something nicer (say you have a lens-effect as if the player was looking through binoculars, then you can first render some kind of image of the binoculars' peep hole(s) to decorate the surrounding if the viewpoint).

>>2) This code must affect the whole view, not just a portion.
That's not a big deal, people typically arrange rendering using scene-graphs, typically, something like: MainScene contains and renders a GUIScene and MainView; MainView contains and renders a WorldView (which it could just render to a texture and apply the distortion). The objects you render just belong to one scene and get rendered onto their parent's scene. This is good for being able to switch scenes and rendering methods on-the-fly (like when you hit the "change camera" button in a game, you only need to rearrange the scene-graph, no need to reload anything which would be time-consuming).

>>These complications are because I wasn't able to change the code to an orthographic projection. The screen somehow ended up blank.
This happens because when you set the view to orthographic, it has to clip the objects at depth of more than 0. And since you rendered your grid at 0 in z-coordinate, it will be "in front" of the screen and will not appear. Just setting the depth to 0.5 should fix it (I think.. just play around with depth and glOrtho() and you should eventually get it to work).

I agree, NeHe is by far the best place to start with OpenGL (and it also carries you a heck of a long way to do some nice effects). At some point, it is also good to give the Redbook a read-through as well (especially the beginning that really gets you to understand how OpenGL works and what happens behind those function calls) (you can just start with the v1.1 that is online).

To clear things up, I would be able to solve the 2 complications I listed once I knew how to render an orthographic view.

As things turn out, I have done it! These are the updated functions:

void Transform(int i, int j, double *ix, double *iy) {
    double x, y, xnew, ynew;
    double r, theta, rnew, thetanew;
    
    x = i / (ScreenSizeX/2.0) - 1;
    y = j / (ScreenSizeY/2.0) - 1;
    r = sqrt(x*x + y*y);
    theta = atan2(y, x);
    
    //NONE
        xnew = x;
        ynew = y;
    //SINE XY
        //xnew = sin(PID2*x);
        //ynew = sin(PID2*y);
    //SINE R
        //rnew = sin(PID2*r);
        //thetanew = theta;
        //xnew = rnew * cos(thetanew);
        //ynew = rnew * sin(thetanew);
    //SQUARE XY
        //xnew = x*x*SIGN(x);
        //ynew = y*y*SIGN(y);
    //SQUARE R
        //rnew = r*r;
        //thetanew = theta;
        //xnew = rnew * cos(thetanew);
        //ynew = rnew * sin(thetanew);
    //ASIN XY
        //xnew = asin(x) / PID2;
        //ynew = asin(y) / PID2;
    //ASIN R
        //rnew = asin(r) / PID2;
        //thetanew = theta;
        //xnew = rnew * cos(thetanew);
        //ynew = rnew * sin(thetanew);
    
    *ix = (xnew + 1) / 2.0;
    *iy = (ynew + 1) / 2.0;
}
void CreateGrid(void) {
    glMatrixMode(GL_PROJECTION);								// Select Projection
	glPushMatrix();												// Push The Matrix
	glLoadIdentity();											// Reset The Matrix
	glOrtho( 0, ScreenSizeX, ScreenSizeY, 0,-1, 1);				// Select Ortho Mode
	glMatrixMode(GL_MODELVIEW);									// Select Modelview Matrix
	glPushMatrix();												// Push The Matrix
	glLoadIdentity();											// Reset The Matrix
    
    int i, j, n = 20;
    double x, y;
    
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glBindTexture(GL_TEXTURE_2D, EndTexture);
    glColor3f(aWhite);
    for (i = 0; i <= ScreenSizeX; i += n) {
       glBegin(GL_TRIANGLE_STRIP);
       for (j = 0; j <= ScreenSizeY; j += n) {
          Transform( i  , j, &x, &y);
          glTexCoord2f( x, y); glVertex3f( i   , ScreenSizeY -j, 0.0);
          Transform( i+n, j, &x, &y);
          glTexCoord2f( x, y); glVertex3f((i+n), ScreenSizeY -j, 0.0);
       }
       glEnd();
    }
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);
	
    glMatrixMode( GL_PROJECTION );								// Select Projection
	glPopMatrix();												// Pop The Matrix
	glMatrixMode( GL_MODELVIEW );								// Select Modelview
	glPopMatrix();												// Pop The Matrix
}

void DrawGLScene(void);
void RenderToTexture() {						// Renders To A Texture
    DrawGLScene();
    
	glBindTexture(GL_TEXTURE_2D, EndTexture);
	// Copy Our ViewPort
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, ScreenSizeX, ScreenSizeY, 0);
    
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And Depth Buffer
}

The value n in CreateGrid() is how detailed you want the final display to be. 20 seems to strike a nice balance between detail and performance for my 800x600 window.

Give me some more time, and I think I'll be able to figure out how to distort only a portion of the screen.

Hey everybody,

Yup, I've done it. I've even compacted it so you can get the distortion effects with just one function call.

This is the header (called Distortion.h):

#ifndef DISTORTION_H_INCLUDED
#define DISTORTION_H_INCLUDED

#define SIGN(x) (x < 0 ? (-1) : 1)

#define PID2 1.5707963268

GLuint EndTexture;
GLuint EmptyTexture() {											// Create An Empty Texture
	GLuint txtnumber;											// Texture ID
	unsigned int* data;											// Stored Data

	// Create Storage Space For Texture Data (128x128x4)
	data = (unsigned int*)new GLuint[((ScreenSizeX * ScreenSizeY)* 4 * sizeof(unsigned int))];
	ZeroMemory(data,((ScreenSizeX * ScreenSizeY)* 4 * sizeof(unsigned int)));	// Clear Storage Memory

	glGenTextures(1, &txtnumber);								// Create 1 Texture
	glBindTexture(GL_TEXTURE_2D, txtnumber);					// Bind The Texture
	glTexImage2D(GL_TEXTURE_2D, 0, 4, ScreenSizeX, ScreenSizeY, 0,
		GL_RGBA, GL_UNSIGNED_BYTE, data);						// Build Texture Using Information In data
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

	delete [] data;												// Release data

	return txtnumber;											// Return The Texture ID
}

#define DISTORT_NONE      0
#define DISTORT_SINE_XY   1
#define DISTORT_SINE_R    2
#define DISTORT_SQUARE_XY 3
#define DISTORT_SQUARE_R  4
#define DISTORT_ASIN_XY   5
#define DISTORT_ASIN_R    6
typedef unsigned short DistortMode;

void Transform(DistortMode dm, int i, int j, double *ix, double *iy) {
    double x, y, xnew, ynew;
    double r, theta, rnew, thetanew;
    
    x = i / (ScreenSizeX/2.0) - 1;
    y = j / (ScreenSizeY/2.0) - 1;
    r = sqrt(x*x + y*y);
    theta = atan2(y, x);
    
    switch (dm) {
        case DISTORT_NONE:
            xnew = x;
            ynew = y;
            break;
        case DISTORT_SINE_XY:
            xnew = sin(PID2*x);
            ynew = sin(PID2*y);
            break;
        case DISTORT_SINE_R:
            rnew = sin(PID2*r);
            thetanew = theta;
            xnew = rnew * cos(thetanew);
            ynew = rnew * sin(thetanew);
            break;
        case DISTORT_SQUARE_XY:
            xnew = x*x*SIGN(x);
            ynew = y*y*SIGN(y);
            break;
        case DISTORT_SQUARE_R:
            rnew = r*r;
            thetanew = theta;
            xnew = rnew * cos(thetanew);
            ynew = rnew * sin(thetanew);
            break;
        case DISTORT_ASIN_XY:
            xnew = asin(x) / PID2;
            ynew = asin(y) / PID2;
            break;
        case DISTORT_ASIN_R:
            rnew = asin(r) / PID2;
            thetanew = theta;
            xnew = rnew * cos(thetanew);
            ynew = rnew * sin(thetanew);
            break;
    }
    
    *ix = (xnew + 1) / 2.0;
    *iy = (ynew + 1) / 2.0;
}
void CreateGrid(int StartX, int StartY, int SizeX, int SizeY, DistortMode dm, int dd) {
    glViewport(StartX, StartY, SizeX, SizeY);
    
    glMatrixMode(GL_PROJECTION);							// Select Projection
	glPushMatrix();											// Push The Matrix
	glLoadIdentity();										// Reset The Matrix
	glOrtho( 0, ScreenSizeX, ScreenSizeY, 0,-1, 1);			// Select Ortho Mode
	glMatrixMode(GL_MODELVIEW);								// Select Modelview Matrix
	glPushMatrix();											// Push The Matrix
	glLoadIdentity();										// Reset The Matrix
    
    int i, j;
    double x, y;
    
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glColor3f(1.0f, 1.0f, 1.0f);
    glBindTexture(GL_TEXTURE_2D, EndTexture);
    for (i = 0; i <= ScreenSizeX; i += dd) {
        glBegin(GL_TRIANGLE_STRIP);
        for (j = 0; j <= ScreenSizeY; j += dd) {
            Transform(dm, i, j, &x, &y);
            if (x >= 0 && x <= 1) { if (y >= 0 && y <= 1) {
                glTexCoord2f(x, y); glVertex3f( i, ScreenSizeY-j, 0);
            }}
            Transform(dm, i+dd, j, &x, &y);
            if (x >= 0 && x <= 1) { if (y >= 0 && y <= 1) {
                glTexCoord2f(x, y); glVertex3f((i+dd), ScreenSizeY-j, 0);
            }}
        }
        glEnd();
    }
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);
	
    glMatrixMode(GL_PROJECTION);							// Select Projection
	glPopMatrix();											// Pop The Matrix
	glMatrixMode(GL_MODELVIEW);								// Select Modelview
	glPopMatrix();											// Pop The Matrix
	
	glViewport(0, 0, ScreenSizeX, ScreenSizeY);
}

void DrawGLScene();
void RenderToTexture(int StartX, int StartY, int SizeX, int SizeY) {
	glBindTexture(GL_TEXTURE_2D, EndTexture);
	// Copy Our ViewPort
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, StartX, StartY, SizeX, SizeY, 0);
}

void Distort(double StX, double StY, double SzX, double SzY, DistortMode dm, int dd) {
    int StartX = (int)(ScreenSizeX*StX);
    int StartY = (int)(ScreenSizeY*StY);
    int SizeX  = (int)(ScreenSizeX*SzX);
    int SizeY  = (int)(ScreenSizeY*SzY);
    
    RenderToTexture(StartX, StartY, SizeX, SizeY);
    CreateGrid(StartX, StartY, SizeX, SizeY, dm, dd);
}

#endif

Just find all the ScreenSizeX and ScreenSizeY and replace it with your own screen resolution and it should work like a charm.

The function you call would be:

Distort(double, double, double, double, DistortMode, int);

First 4 parameters take the area's XCoord, YCoord, XSize and YSize respectively. Their possible values range from 0 to 1 in terms of your screen size.
Fifth parameter is what type of distortion you want. The different types are listed before Transform() and you can even add your own modes of distortion.
Sixth (last) parameter is how much detail you want in your distortion.
I was testing out medium-sized distortions, and a value of 10 works fine.

Now I just need some way to 'assign' distortions to 2D or 3D objects. Right now it only supports values in accordance to the screen resolution. This is not good when I have a rectangular screen and a translated view. Help please?

Hey guys,

I've spent a few days trying to find a solution by trial-and-error. I get close, but the distortion is not seamless.

Let's assume the 'object' mentioned below is causing distortion.
Let me try to explain some things I found out...

This 3D Distortion method would be to get a texture from a 3D space, and render it at that exact same position (distorted, of course) facing the camera. So this isn't real 3D distortion and can be considered "cheating" but it is a solution nonetheless.
The problem faced here is that the texture grabber function, glCopyTexImage2D(), only accepts orthographic coordinates and not rendered-world coordinates. This is not the entire problem however.
The problem would not be so bad if I am able to ignore just the radius of the distortion when grabbing and rendering, as the apparent radius would be affected by 3D Zoom (modified by the Z Coord). If that were the case I could just pinpoint the object's X and Y Coords on the Z = 0.0f plane and copy the texture from there, and render on the Z = 0.0f plane as well.
The real problem is that the object's apparent X and Y Coords on the Z = 0.0f plane do not match the object's absolute X and Y Coords. I can get close with estimated values, but I do not know how to calculate this value during runtime.

So to make it clear, glCopyTexImage2D() works only on the Z=0 plane, and the object's apparent X and Y Coords and radius vary with the depth of the object.
This would all be fine if glCopyTexImage2D() did Depth calculations and included a depth parameter, but unfortunately it doesn't.

This all breaks down to how OpenGL does depth calculations. If I know how to do it, I might be able to get this to work.

This is how I intend to do it:

First I retrieve the object's X and Y Coords and radius, then modify these values with the depth calculations before sending them to glCopyTexImage2D(). glCopyTexImage2D() will then grab the (2D) space directly above the object just like it would if you zoomed the function in (which is impossible). I can then render the (distorted) image at exactly where I copied the image from, at the Z=0 plane.

I now have some code that works perfectly on my application.

This is some new code:

void wRenderToTexture(GLfloat CtX, GLfloat CtY, GLfloat Radius, int &StartX, int &StartY, int &Size, int &d) {
    int ScreenMod = (int)(ScreenSizeX * 0.909f); //727
    int StX = (int)((CtX-Radius+1.0f)/2 *ScreenMod) +36;
	int StY = (int)((CtY-Radius+1.0f)/2 *ScreenMod) +((int)(ScreenSizeY-ScreenMod)/2) +2;
	int Sz = (int)(Radius*ScreenMod);
    
	glBindTexture(GL_TEXTURE_2D, EndTexture);
	// Copy Our ViewPort
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, StX, StY, Sz, Sz, 0);
    
    StartX = StX;
    StartY = StY;
    Size = Sz;
    d = ScreenMod;
}

void wDistort(GLfloat CtX, GLfloat CtY, GLfloat Radius, DistortMode dm, GLfloat dd) {
    int StX = 0;
    int StY = 0;
    int Sz = 0;
    int d = 0;
    
    wRenderToTexture(CtX, CtY, Radius, StX, StY, Sz, d);
    
    d = (int)(d*dd);
    CreateGrid(StX, StY, Sz, Sz, dm, d);
}

Note that I said "my application". I mean this code works only with my current settings. Since I do not know the details of the calculations, this is the best I can do with my application settings.
I am using 800x600 screen with a default depth translation of -2.0f.

The variables that I think need changing are all in the wRenderToTexture() function.
1) ScreenMod: ScreenSizeX * xxx (0.909f)
2) StX: ... +xxx (36)
3) StY: ... +xxx (2)

Anyone knows how to calculate these values?

I now have some code that works perfectly on my application.

This is some new code:

void wRenderToTexture(GLfloat CtX, GLfloat CtY, GLfloat Radius, int &StartX, int &StartY, int &Size, int &d) {
    int ScreenMod = (int)(ScreenSizeX * 0.909f); //727
    int StX = (int)((CtX-Radius+1.0f)/2 *ScreenMod) +36;
	int StY = (int)((CtY-Radius+1.0f)/2 *ScreenMod) +((int)(ScreenSizeY-ScreenMod)/2) +2;
	int Sz = (int)(Radius*ScreenMod);
    
	glBindTexture(GL_TEXTURE_2D, EndTexture);
	// Copy Our ViewPort
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, StX, StY, Sz, Sz, 0);
    
    StartX = StX;
    StartY = StY;
    Size = Sz;
    d = ScreenMod;
}

void wDistort(GLfloat CtX, GLfloat CtY, GLfloat Radius, DistortMode dm, GLfloat dd) {
    int StX = 0;
    int StY = 0;
    int Sz = 0;
    int d = 0;
    
    wRenderToTexture(CtX, CtY, Radius, StX, StY, Sz, d);
    
    d = (int)(d*dd);
    CreateGrid(StX, StY, Sz, Sz, dm, d);
}

Note that I said "my application". I mean this code works only with my current settings. Since I do not know the details of the calculations, this is the best I can do with my application settings.
I am using 800x600 screen with a default depth translation of -2.0f.

The variables that I think need changing are all in the wRenderToTexture() function.
1) ScreenMod: ScreenSizeX * xxx (0.909f)
2) StX: ... +xxx (36)
3) StY: ... +xxx (2)

Anyone knows how to calculate these values?

I've found that the ScreenMod value is actually calculated like this:

int ScreenMod = (int)(1454/(-Depth));

Anyone knows what 1454 roughly equates to?
This value might change with the screen ratio, but I was unable to check that.

The XAlign is affected by both Screen Size and Depth. These are my findings for my 800x600 resolution when changing the depth:

-1.0f -> -329
-2.0f ->   36
-3.0f ->  158
-4.0f ->  218
-5.0f ->  255

These values are only a visual estimate. You can probably +- 5 to these.
These do not seem to follow and pattern that I thought of.

The YAlign should be a constant somewhere between 0 and 2. I go for 1.

Hey there - I feel a bit bad resurrecting such an ancient thread but I must say that the above piece of code from Weird Nerd is amazingly done and appears to be the only solution I've been able to find on the web that "just works" right after inserting into any code and running it - without any need for headers. Great work indeed!!!

I'm only wondering if it could be possible to "limit" the distortion to just a circle of a given radius? Right now it only appears to work with the entire screen and I'm trying to make it work just within a circle that dynamically increases or decreases its radius.

Thanks in advance for any advice!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.