Realistic FFT Ocean

Yes, yes I do. So Iā€™ve been thinking about how to implement the foam for quite a while. Iā€™ve been specifically setting my eyes on 2 methods:

  • The more performant one, but less accurate method: basing it off of height - The way NVIDIA went in GPU Gems 2
  • The less performant one, but more accurate: using a Jacobian determinate

Eventually thought I decided to go with the way that NVIDIA went, basing it off of height. I mainly chose this since if you look at a Jacobian graph (image below) it closely resembles the height, and if we just use the height, something we already have available without extra calculations, then weā€™ll be able to implement it with minimal performance loss.

image
(Tessendorf 2001)

And hereā€™s the finished product: (I forgot to invert the values :sweat_smile: )

6 Likes

Iā€™ve come back to this project, ā€¦for like the third time. A few changes were made and more may come. Most of the work is going to be on optimizing some of the math and caustics, as you can see Iā€™ve actually already done something with the caustics. Iā€™ve made them blend into the texture of the seabed (Texture size is still limited to the Mesh resolution).

Although this is not done without issues, if you look closely some of the rocks donā€™t tend to behave how they should be. This is because theyā€™re in a different UV position on the texture. The way to fix this would be to get the UV of that specific vertex and change the texture there. Which isnā€™t currently possible, as the only transformation between UV and World space is by getting the UV space of a Vertex. But since each vertex is not a single pixel on the texture, that wonā€™t work. Meaning, that this is best used on a UV map that is a top down view of the mesh.

For the near future, Iā€™m planning to make the caustics take in account shadows. Letā€™s also not forget that weā€™ve still got an entire underwater to make, this is only the start. In the upcoming days and weeks Iā€™ll mostly be focusing on the underwater parts of this, so detecting if youā€™re underwater, caustics accounting for shadows, and an underwater effect. Hopefully by the next post I make all or at least some of these things will have been already finished.

6 Likes

it looks great but why did the game in both studio and roblox broke tho?

1 Like

So, it seems that a recent major update to both the Editable Mesh and Image has broken everything, not surprised since it was (and still is) a beta feature.

Iā€™m going to be gradually fixing it, hopefully youā€™ll also see improvements in performance, or at least Iā€™m hoping so. Looking at the new API, it seems that itā€™s a lot more verbose. Iā€™ve already got the movement and color of the vertices back in a working state and Iā€™ll be gradually fixing the other features.

:smiling_face_with_tear:

2 Likes

Everything is now in a working state!

This whole new API change felt really rushed and unstable, the previous version was much more reliable and better to work with. Iā€™ve had to hard code certain things such as the image resolution, because theyā€™ve decided to remove the Resize() function and not create an alternative (yet). Iā€™ve also decided to hard code stuff like the VertexID, NormalID and ColorID, so that may break in the future, so Iā€™ve already prepared a non hard coded version. Honestly I slightly hope that thereā€™s a new API update, not because Iā€™m some sort of masochist who wants to rewrite it again, but because this new API is utterly garbage. Itā€™s unnecessarily complex and verbose, while missing past features and being more unstable than before. While containing even more bugs than the past version, obscure bugs such as the mesh not rendering if all the vertices are on the same Y level, texture content not changing if you use CreateEditableImageAsync instead of CreateEditableImage, color values went from 0-1 to 0-255 for some reason.

Iā€™m unsure of the performance improvements, mainly because Iā€™m using a VM, but from the performance Iā€™ve seen it seems to be better than before.

4 Likes

its not working any more do you know why

1 Like

I just tried it and it seems to be working fine for me. Although, I did also fix an issue with WaitForChild returning an infinite yield, so if that was the issue itā€™s fixed now.

If this didnā€™t fix it then could you copy the errors from your output and any steps to reproduce it?

its still not working do you know why

Thank you, been wanting to test it out. I was talking to DevVexus about it and if we do a bunch of optimization(Lerping, etc) methods we could get it at a stable rate mabye even for a game.

1 Like

I believe this is your issue, accounting the fact that IcyMonstrosity doesnā€™t have the issue and you do.

If it is, I havenā€™t found a solution.

Iā€™m not aware of any ways to give you permission to use the image, no clear way to do it through the development items menu at least. Best I can do is give yā€™all the image and then have you import it yourself and modify the floor texture variable.

image
PS: image is 96x96, because Roblox cannot implement a full API update and didnā€™t include a lot of features for EditableImages, including the resize function

How did you get the caustics to cast onto parts on the sea floor? i.e how did you get the caustics texture to appear on top of parts on the floor

The caustics themselves sadly donā€™t adapt to other parts, they only work on the floor texture. Iā€™ve thought of adding that in, and maybe even casting shadows but the performance costs would just be through the roof.

If youā€™re curious on how I change the texture then I just simply cache the texture buffer and write the RGBA depending on the dot product of the normal and sun. (with an offset)

YOOOO!! :tada:

Roblox just published an update making In-Experience Mesh & Editable API available in live experiences!

Now you can fully check out the experience yourself without any tinkering

(also added a time changing script to showcase the mesh normals and caustics)

Iā€™ve also witnessed it being quite unstable, working for some people while not for others. Confirmed that itā€™s an issue with mobile

7 Likes

@IcyMonstrosity its laggy but otherwise its awesome

1 Like

DAMN
image

Hey man, i was wondering, when reading through your code (at the moment im experimenting with editable meshes myself), I have 2 questions, one,


how did you come up with those numbers that are applied to the vertexID inorder to find the relating id, eg the color id or normal id,

and question 2, would finding this out fix my current problem with my flipbook-based fft ocean
problem:

For some reason each of the IDs (Vertex, Triangle, Normals) have different starting positions, I got this number just by subtracting that offset. Thereā€™s also a version without the hard coded values which has to index a table each time it wants to get the relevant ID. This was primarily a slight performance decision, itā€™s a lot better to just add N rather than indexing a table with N.

Potentially? Iā€™m unsure of the cause of the issue you have but the UV coordinate of the vertices might be the issues. I donā€™t actually use UV coordinates here, since the color is based on the vertex.

How do you mean, ā€˜subtractingā€™ the offset, wouldnt that number just be a vector2? or are you talking different positions in the array?,

the reason i say this, is because :setfaceuvā€™s constantly gives the error ā€˜invalid idā€™ even after finding the offset/using your example.


Iā€™m talking about the ID, which is an integer, you can just do this by keeping count of the number of UV IDs and then subtract the ID that returns from :SetFaceUVs with that number, giving you a constant number.

The problem youā€™re facing is probably because of an incorrect vertex ID. You can compare it with my implementation if the values arenā€™t the same:

for X = 1, FOURIER_SIZE-2 do
		for Y = 1, FOURIER_SIZE-2 do
			local Vertex1 = X * FOURIER_SIZE + Y
			local Vertex2 = Vertex1 + 1
			local Vertex3 = (X + 1) * FOURIER_SIZE + Y
			local Vertex4 = Vertex3 + 1

			
			local Face = OCEAN_MESH:AddTriangle(4294967296+Vertex1, 4294967296+Vertex2, 4294967296+Vertex3)
			OCEAN_MESH:SetFaceColors(Face, {12884901888+Vertex1, 12884901888+Vertex2, 12884901888+Vertex3})
			OCEAN_MESH:SetFaceNormals(Face, {8589934592+Vertex1, 8589934592+Vertex2, 8589934592+Vertex3})		

			local Face = OCEAN_MESH:AddTriangle(4294967296+Vertex2, 4294967296+Vertex4, 4294967296+Vertex3)
			OCEAN_MESH:SetFaceColors(Face, {12884901888+Vertex2, 12884901888+Vertex4, 12884901888+Vertex3})
			OCEAN_MESH:SetFaceNormals(Face, {8589934592+Vertex2, 8589934592+Vertex4, 8589934592+Vertex3})		
		end
	end