Making an Image Concave in Java

205 Views Asked by At

I had a quick question, and wondered if anyone had any ideas or libraries I could use for this. I am making a java game, and need to make 2d images concave. The problem is, 1: I don't know how to make an image concave. 2: I need the concave effect to be somewhat of a post process, think Oculus Rift. Everything is normal, but the camera of the player distorts the normal 2d images to look 3d. I am a Sophmore, so I don't know very complex math to accomplish this.

Thanks, -Blue

1

There are 1 best solutions below

0
On

If you're not using any 3D libraries or anything like that, just implement it as a simple 2D distortion. It doesn't have to be 100% mathematically correct as long as it looks OK. You can create a couple of arrays to store the distorted texture co-ordinates for your bitmap, which means you can pre-calculate the distortion once (which will be slow but only happens once) and then render multiple times using the pre-calculated values (which will be faster).

Here's a simple function using a power formula to generate a distortion field. There's nothing 3D about it, it just sucks in the center of the image to give a concave look:

int distortionU[][];
int distortionV[][];
public void computeDistortion(int width, int height)
{
    // this will be really slow but you only have to call it once:

    int halfWidth = width / 2;
    int halfHeight = height / 2;
    // work out the distance from the center in the corners:
    double maxDistance = Math.sqrt((double)((halfWidth * halfWidth) + (halfHeight * halfHeight)));

    // allocate arrays to store the distorted co-ordinates:
    distortionU = new int[width][height];
    distortionV = new int[width][height];

    for(int y = 0; y < height; y++)
    {
        for(int x = 0; x < width; x++)
        {
            // work out the distortion at this pixel:

            // find distance from the center:
            int xDiff = x - halfWidth;
            int yDiff = y - halfHeight;
            double distance = Math.sqrt((double)((xDiff * xDiff) + (yDiff * yDiff)));

            // distort the distance using a power function
            double invDistance = 1.0 - (distance / maxDistance);
            double distortedDistance = (1.0 - Math.pow(invDistance, 1.7)) * maxDistance;
            distortedDistance *= 0.7; // zoom in a little bit to avoid gaps at the edges

            // work out how much to multiply xDiff and yDiff by:
            double distortionFactor = distortedDistance / distance;
            xDiff = (int)((double)xDiff * distortionFactor);
            yDiff = (int)((double)yDiff * distortionFactor);

            // save the distorted co-ordinates
            distortionU[x][y] = halfWidth + xDiff;
            distortionV[x][y] = halfHeight + yDiff;

            // clamp
            if(distortionU[x][y] < 0)
                distortionU[x][y] = 0;
            if(distortionU[x][y] >= width)
                distortionU[x][y] = width - 1;
            if(distortionV[x][y] < 0)
                distortionV[x][y] = 0;
            if(distortionV[x][y] >= height)
                distortionV[x][y] = height - 1;
        }
    }
}

Call it once passing the size of the bitmap that you want to distort. You can play around with the values or use a totally different formula to get the effect you want. Using an exponent less than one for the pow() function should give the image a convex look.

Then when you render your bitmap, or copy it to another bitmap, use the values in distortionU and distortionV to distort your bitmap, e.g.:

for(int y = 0; y < height; y++)
{
    for(int x = 0; x < width; x++)
    {
        // int pixelColor = bitmap.getPixel(x, y);  // gets undistorted value
        int pixelColor = bitmap.getPixel(distortionU[x][y], distortionV[x][y]);  // gets distorted value
        canvas.drawPixel(x + offsetX, y + offsetY, pixelColor);
    }
}

I don't know what your actual function for drawing a pixel to the canvas is called, the above is just pseudo-code.