-
Notifications
You must be signed in to change notification settings - Fork 145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Water Simulation? #20
Comments
Hey I did it. Not the real-time flooding part, but the part where water instantly floods what it can, being the only parameter to it that it should never flood anything taller than its origin point. (Which is a gross simplification, given pascal law and all). So, the idea is simple, for it to work fast I developed a data structure (not compressed... which is bad), that stores every possible 2d surface for a given 3d lake/ocean. I can make a pull request if you guys think it is a good idea. Oh, but here is the kicker, and this Scheidecker probably knew all the time: About the water. You can drag and drop any water material to the surface material of a given block material. Which is awesome. Here is a screenshoot of my results: (You can find the water material I use here: https://github.com/UE4-OceanProject/OceanProject) screenshoots: And by doing some tweaking now the blocks under water blocks are rendered too: |
That looks awesome! |
Give me a sec (maybe a couple days) to clean it up so it is ready to merge, and then I will make the pull request. About the data structure, on a basic level it stores the FInt3 Coordinates of the bricks that conform each one of the XY slices of a XYZ lake. Something I am working on is to reuse that information for custom pathfinding. Because if you use the collision of BrickGrid along with UE4 NavMesh you will get unrealistic movement: People will find no trouble climbing unnecesary elevations. But if you use the data of the lakes, then you could develop your own pathfinding (which could be cheaper) where the people will always walk on flat surfaces, unless its not possible. |
Nice to hear that somebody is actually working here 👍 Looking forward :) |
My goal is an RTS on top of a voxel world, whats yours? |
A crossover between Starbound + Minecraft + Factorio 😂 Not even sure if I bring this to a certain point |
Sounds like you are going to work a lot more than I on the gameplay dynamics. Factorio especially, is all about that. Tons of different options and winning strategies. |
Yep, and I'm not sure if I even finish this, but if I do, it'll go on Steam :) |
Greenlight is the way to go. Kickstarter + Greenlight, really. Kickstarter can be used for the money, but the exposure is in my opinion more important. There you can find artists ready to work on the art on top of your game. Maybe not kickstarter, is not like I have done proper research, but on a general scale, that would be the way to go. Develop the logic, expose the product, find the team (ussually the artists), and then Greenlight. Maybe I am wrong but, again, its not like I am close to that part of the developing process so. What I sometimes find weird is what is the motivation of Andrew to build this absolutly fantastic piece of code. I mean, you want to make your game, I want to make mine, whats up with the creator of the most complicated part of the work we are working on top of? I would not be suprised if tomorrow a game is shipped and it was made by Andrew. I am ust curious what genre would it be of. One thing is certain, it would have a Minecraft feel to it for sure. |
I don't think he is working on this currently. I hate people calling games "Minecraft Ripoffs" just because they share the way of doing a terrain and a building system... |
Indeed! Is like minecraft has the monopoly of voxel use in games! That said, given the popularity of it, it can be said that games using cubes as the representation of voxels have a similar aestethic. |
Does your simulation also generate water lakes through the world or does it only support "oceans" yet? |
Not really a simulation, but a reduntant database. The information I am creating is implicit on the Region.BrickContents. It satifies the following query: What bricks can I "flood" from this location. Where "flood" means access all adjacent empty bricks of the same height or less. You could access this information by using a search algorithm every time. Or you could "cook" it. Which bring us to the redundant database. It works like this. Inside the function SetBrick it checks if the brick set is of a given material. Lets say the material that floods depressions is 1. And the material used for the water effect is 9. Then it accesses with the given coordinate to an index file that says what lake this block belongs to. On this file, absolutly all the blocks coordinates are linked to LakeIndexes. Non Empty bricks has a LakeIndex of -1, as they cannot be flooded. A LakeIndex is the key to then access the Lake information itself. Right now if you see a LakeIndex of 4, it means the LakeInitialCoordinate was X = 0, Y= 0, and Z = 4. Anyway. With the LakeIndex found, now you can access the lake information, which is inside the file that has the LakeIndex as name. Inside the file you can access all the floodable bricks, and for each one of them you change their material and boom. The lake/ocean is flooded. To make things more complicated: Everytime I talk about accesing a Lake information, well, I should be saying LakeSlice information. Because there are as many slices in a lake as possible floodable heights. So say you are flooding a recipient at the middle, for it to flood only to the middle it would use the LakeSlice that correspond to the middle of it, not the one at the top. So, with that out of the way, how then can you flood the LakeSlices underneath the one you are flooding?... So, in this way, now you store all the floodable bricks for each LakeSlice, and the indexes of the underneath LakeSlices too. Next complexity step: How to simulate the breaking of a dam? You add a third reduntant information to the data structure. Now each LakeSlice stores it X, Y, and -X, and -Y frontiers. Each one is an array of brick coordinates. This way when you destroy a brick you check its LakeIndex, or LakeSliceIndex, whatever. Uhm... well, not literally the coordinates of the brick you are goind to destroy, but the one adjacents to it. That sounds right. Okay so you access the LakeSliceIndex of each one of the adjacent bricks and if that adjacent brick belongs to the frontier of the LakeSlice then you create a flooding brick on the place of the brick you just destroyed. And boom, now you can breaks dams, or any water recipient, and expect flooding. |
@miguelemosreverte, that looks great! I'd definitely merge a pull request to make translucent bricks render correctly. If you submit a PR for water flow, I'd consider merging it, but only if I was prepared to support the code (though I know my support lately has been lacking). Even if I don't merge it, the PR can still be helpful for other people who want to use your changes. From reading your overview of how it works, my primary concern would be the performance of recomputing the flood volumes when a brick changes. If you add or remove a single brick, it could cause the flooding information to change over a very large area, so it might be hard to do incrementally. I think that's an argument for something more like Minecraft, Dwarf Fortress, and other games that implement water that flows from block to block in real-time: it localizes the effect of modifying the bricks.
BrickGame was a fun side-project I did when UE4 was first released publically, and wanted to provide an example to folks how to implement rendering plugins like this. I've just been doing minimal maintenance work since then, except for my VXGI experiment. You don't have to worry about me competing with you if you want to release a game using this code! |
I knew you where going to be specially attracted to the implementation of translucent bricks, because while flooding algorithms are cool and all, they can made with time and effort. But tweaking the render code? That requires more thought! And you specially would be, if not the only one, the one to know this since you are the creator of it! So, yeah. With that to a side (looking back to it I just added two or three lines of code, its not impresive to look at if you do not know the complexity of the code), about the flooding algorithm: Cellular automaton is a naive algorithm, it does not provide scalability. What I am looking for is to make the information much more redundant, to the point where PC A can say to PC B: "PC A : Hey, remember the LakeSlice 204534 of the Region 300? So, the idea would be that by having a reduntant dabatase communication would be small, if at all needed. About the real-time super cool flooding effects I believe a centralized cloud-based computing could solve the problem. It would give the clients the vertices of the poligon used for the wall of incoming water. Okay, I am rammbling away. I expect to have the Pull request ready for today . If my database teacher heard me talking about redundancies as a good thing he would be so mad... |
When I was thinking about basic water simulation, my idea was pretty simple: When you populate the blocks according to the noise (the three loops), you basicially get every block which is below a limit (like the material selection works right now) - the sea limit. Then when a block is under the sea limit, you create an additional block which goes some values below the original one in the height axis. That forms the ground of the sea. The block you had originally is the new sea block, so that gets the ocean shader on it. Two problems still: aligning the post process volume to fit under the blocks, and second: the transition between non-water and water would be rough, as non-existent. |
Oh do not worry about the post-process volume. Andrew gave us the example on how to create redundant blocks on top of each other: You have the ones you use to render, and all is good. But now what about collision?? Well, as seen in the example given, you create collision boxes in the exact same spot. Do the same with post process and then with Physics Volumes (to add buoyancy forces, for example) and you are done! I believe I should appoint this as my next task now that I see the urgency of it. |
I look forward to test your pull request out! Thanks for contributing to this and helping me with it the same time! |
I guess so, but really, thanks to Andrew. He is exactly what every developer community needs. To code for fun speaks volume of his qualities as a programmer. Is like those olimpic runners that go to "work out" every day and by working out I mean do stuff we mortals can only imagine because we grow tired half way. |
ISP change complicated downloading the repository. Downloading it now. Delay 1 day. |
Oh nice! Could this also allow glass blocks? |
sure. A list of transclucent materials could be implemented so that instead of just checking for material 9 it would check for the ones you added as translucent. |
Nice stuff! I will test it out soon! |
First problem found: All this time it worked because the water flooded until it found a non empty cube. The translucent cube has vertices with index 0 at the sides. This way the only well rendered translucent cubes are the ones surrounded by other cubes: (which had been the case until not long ago): Bassically its a matter of changing the vertex index of the two bottom vertices on the side faces of the translucent cubes. I will get onto it. But for now, you have the same code I used to make translucent surfaces for water. See how the faces at the other side are invisible? Well they are not, they too have vertices with index 0 and go straight down to the corner of the region. Same problem with the top surface faces: Right now it only works right if it has non empty neighboors to the sides: It should be easy to fix. |
For you my friend, for you 😂 👍 |
it looks like there is an vertex missing to make it a rectangle.. |
Couldn't you just add another vertex to that position (maybe there are two missing because of the lower one of the two)? |
Exactly. Trouble is to understand why this has gone wrong, since in theory this should not be happening. But... oh well. It will be a matter of looking at the code for a while sipping coffee. Will update immediately when the culprit is found. Edit 1: I think I solved it: Debugging breakpoints show that only once per translucent brick the boolean IsTranslucentBrick is true. Which sound right, right? Not at all. That variable used to be called something like IsWaterLocalVertex, or along something along those lines. The thing it that every time that was true a vertex was created. And behold, it was only true once per translucent brick. So only one vertex was created. What was I thinking. Anyway. That has been changed, and the code is bug free now. Enjoy your glass cubes! |
Awesome, but why does the water start expanding horizontally in the air? |
i am trying to find that out right now. The algorithm is fine, bassically it says if empty downwards go down, if not then expand to the sides. The bug happens when a brick that is on the list of the ones that have water is on top of recently flooded bricks. Then it acts like this bricks are the ground and it expands too. I will solve it by saying it only can expand to the sides if the block underneath is not water. Not without permission, that is. Later on I would have to work on that. So that once the water touches ground it expands, and later on it goes higher in height and expands again. |
Thought that also. How do you manage which block is water? Again a hardcoded material index? |
yup. bad habit of mine. |
fixed the bug, uploading video |
Looks cool, much better like Minecraft actually 😂 |
Did this actually evolved out of one water source? Isn't it a bit much? 😂 |
3 block sources, but still, lots of water |
Is this bad or good? |
I mean, is not like all of that water came out of ust one single source, so its good. It came from three. Hey I am working on the water vertices: Main problem: How to control them individually! (Probably c++ would do the trick) |
Does this work as intended? |
No! WIP! |
If you take a look at the materials created by Scheidecker, they all hack FVertexColor, I believe, and use its alpha to send the uint8 value of the AmbientOcclussion. We could copy that so that the C++ info is used by WorldPositionOffset. |
The AmbientOcclusionFactor was hacked to send zeroes or ones depending on the face of the brick. If the face was the top, 1 was sent and that allowed for WorldPositionOffset to work. |
That looks cool! Is this depending on how much water the block before has? So if you spill water on the ground, the last one is really flat? |
Not yet, but as you can see, we are getting there! |
Wrong picture? :D |
No! The value of the Vertex Color AmbientOcclusionFactor is now whats added to the Z component of VertexNormalWS. |
Yeah now it is right, first of you had two times the same picture inside :) Keep me in contact! |
hey with BFS implemented and WorldPositionOffset modifying the top faces of the water bricks I think you have a nice starting point to work towards water simulation. I must start spending more time studying so I am going to let you continue on your own. Some tips: .By using AmbientOcclusionFactor now the bricks that surround water are really dark, thats a bug that requires fixing |
I think they just check how many iterations are already done and have a limit there.. I only would need to check if it just expands horizontally.. |
After all this time I finnally made a somewhat cleaner version of the implementation of the database, both the one of the BrickContents and the one about the precomputed flooding of the water. |
How's your implementation of water going? |
Okay, lets get to a real hot topic. Water simulation? How would I proceed? And, how do I generate just a simple ocean? I think I need to drop my project because this is all stuff I'm not aware of 😢
The text was updated successfully, but these errors were encountered: