Hello Guest

Help with getting height from a FFT ocean texture

  • 1 Replies
  • 1203 Views
Help with getting height from a FFT ocean texture
« on: July 07, 2022, 18:39:01 »
Hello everyone,

I'm here looking for help with an issue I've been losing hair from.

I am currently making a game in Java & lwjgl and everything have so far gone OK but I feel like I've hit a wall with this problem I have.

I am trying to do bouyancy physics for my FFT ocean so for that I need to be able to get the height from a world position. Easy thing I thought since when I generate the ocean I have a texture "dy" that is pretty much the height of all the waves. Here is the code I currently have to get the height
Code: [Select]
public float getHeight(Vector3f worldPosition, float offset) {
       
        // Ignore y coordinate
        Vector3f wp = new Vector3f(worldPosition.x, 0, worldPosition.z);
        Vector2f uv = new Vector2f(wp.x, wp.z);
       
        float x = uv.x;
        float y = uv.y;

        int resolution = fft.getResolution();
        int size = resolution * resolution;

        // We create a floatbuffer to store all pixels from the DY texture
        FloatBuffer fb = BufferUtils.createFloatBuffer(size);
        glBindTexture(GL_TEXTURE_2D, fft.getDy().getId());
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, fb);
       
        // get the val from the x y coordinate
        float val = (x + y * resolution);

        // Keep it at a positive value
        val = Math.abs(val);
        // And keep the value within the size of the buffer
        val %= size;
       
        // Get the raw height
        float r = fb.get((int)val);
       
        // Multiply it by 6 because thats the scale we use in the shader (Not uniform yet)
        float height = r * 6;
       
        return height;
    }
please ignore redundant code and bad practices, I will optimize everything later I promise

Some extra info

-It *works* when the world position is 0,0,0 and I get index 0 (duh)
-The resolution of the texture is 512 and is repeated * 50
-The ocean is based on the videos from Oreon Engine
-The ocean is scaled by 6000 and moved to -3000 to be centered around 0,0,0

After some more researching I found a youtube video where the he got the height from all three textures (dx, dy, dz). I tried this aswell but still feel kinda lost.
My brain have a hard time with Floatbuffers.

New functions
Code: [Select]
public float getHeight(Vector3f worldPosition) {
        return getWaterHeight(worldPosition);
    }

    private float getWaterHeight(Vector3f position) {
        Vector3f p = new Vector3f(position);
        Vector3f displacement = getWaterDisplacement(p);

        p = new Vector3f(position);
        Vector3f d = new Vector3f(displacement);
        displacement = getWaterDisplacement(p.sub(d));
        p = new Vector3f(position);
        d = new Vector3f(displacement);
        displacement = getWaterDisplacement(p.sub(d));
        p = new Vector3f(position);
        d = new Vector3f(displacement);

        return getWaterDisplacement(p.sub(d)).y;
    }

    private Vector3f getWaterDisplacement(Vector3f position) {
        Vector3f p = new Vector3f(position.x, 0, position.z);
       
        int index = (int)p.x + (int)p.z;
        if(index < 0 || index > (fft.getResolution() * fft.getResolution())) {
            System.err.println("Invalid index: " + index);
            return new Vector3f();
        }

        float y = fbY.get(index);
        float x = fbX.get(index);
        float z = fbZ.get(index);
        return new Vector3f(x, y, z);
    }

Also I store the textures inside floatbuffers every frame for testing

Code: [Select]
        fbY.clear();
        glBindTexture(GL_TEXTURE_2D, fft.getDy().getId());
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, fbY);

        fbX.clear();
        glBindTexture(GL_TEXTURE_2D, fft.getDx().getId());
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, fbX);

        fbZ.clear();
        glBindTexture(GL_TEXTURE_2D, fft.getDz().getId());
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, fbZ);

I appreciate any help or suggestions. Thanks!

Re: Help with getting height from a FFT ocean texture
« Reply #1 on: July 17, 2022, 16:02:17 »
I guess this is what you need to do:
Your ocean is 6000f x 6000f.  You repeat your height texture 50 times, that means it consists of 50x50 cells, which are 120f x 120f.



Suppose you are the red dot, and your world position is X: -2820f and Z: -2820f.
First add your offset which is 3000f. So X and Z becomes 180f. Use modulo % and division to get the correct index for your height texture.

Code: [Select]
private void blabla()
{
Vector3f position = new Vector3f(-2820f, 0f, -2820f); // Position red dot
float offset = 3000f; //We need a number between 0...6000, not -3000..3000
float width = 6000f; //Ocean's size
float depth = 6000f;
float cellCount = 50f; //The height texture is repeated 50 times
float cellWidth = width / cellCount; //Each cell is 120f
float cellDepth = depth / cellCount;

Vector3f correctPosition = new Vector3f(position.x + offset, 0f, position.z + offset);
float cellX = correctPosition.x / cellWidth; //returns 1.5f
float cellZ = correctPosition.z / cellDepth;
cellX %= 1f; //return 0.5f, now we can calculate our floatbuffer index
cellZ %= 1f;

int textureWidth = 512; //Heightmap texture is 512 pixels by 512 pixels
int textureHeight = 512;
int rowsSkipped = (int) ((float)textureHeight * cellZ); //Z position is 0.5f, we need to skip 512*0.5f rows
int xOffset = (int) ((float)textureWidth * cellX); //X position is 0.5f, we need to skip 512*0.5f pixels

int index = (rowsSkipped * textureWidth) + xOffset; //This should be the correct index for your floatbuffer
}

I hope this helps :)
« Last Edit: July 17, 2022, 16:14:12 by Martijn »