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
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
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
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!
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.
(https://i.ibb.co/4drPN5Z/cells.png) (https://ibb.co/jRXg41v)
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.
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 :)