BrickGame icon indicating copy to clipboard operation
BrickGame copied to clipboard

Support for complexe shape

Open SirJackblue opened this issue 9 years ago • 70 comments

Hello !

Recently, I started to work on a Voxel Engine, and your project helped me a lot ! I would like to add support for complexe shape, not only draw brick/voxel. I understand how the Brick Render Component works but I have few questions concerning:

  • How unreal normalize UByte4N, normally each byte will be normalized with this formula: divide to 255 = x / max_x * 255, where max_x is the highest byte value and x the current byte value. My question here is does Unreal follow this rule.
  • How uint8 X is converted to UByte4N (I think each bytes has the value of X) ?
  • What is the usage of the 4th bytes of the UByte4N ?
  • If I use a Float4 instead of UByte4N for the ComponentPosition of the DataType, and I normalize it like a UByte4N, can I achieve what I want (complexe bricks like stairs, half-block, etc..) ?

Thank you in advance :)

Cordially, Jackblue

SirJackblue avatar Jul 15 '16 14:07 SirJackblue

Personally, I'd use the Procedural Mesh Component for geometry which doesn't belong to the terrain. Example: I used the Procedural Mesh Component to create runtime-loaded meshes which I can place in the world (select a FBX file, it parses the fbx (using assimp) and gets the information out and populates a procedural mesh with it ). If you want custom shapes for the terrain, I'd take a look at @miguelemosreverte's branch, he implemented wedges on the terrain :smile:

iUltimateLP avatar Jul 15 '16 15:07 iUltimateLP

Thank you for your reply @iUltimateLP !

I prefer to use the terrain grid, for performance and replication purpose, because those shapes I want to draw can be contained inside a brick shape. If I need to render a bigger model, yeah I use directly a mesh.

And I look at @miguelemosreverte's branch and I see nothing concerning vertex, he is using material & Ambient Occlusion if I understood correctly, to animate water.

Cordially, Jackblue

SirJackblue avatar Jul 15 '16 21:07 SirJackblue

Oh, my bad, he removed the custom render code there. Maybe he sees this and answers you that question :)

iUltimateLP avatar Jul 15 '16 22:07 iUltimateLP

Oh! Thankfully I have just finished finals season so I am back, just in time! First of all, sure, lets do it!

Whats the hot thing these days? Last time I checked we where working on the water, hacking the Ambient Occlusion parameter to insert some other data I do not remember. As any hack, it was not a nice solution, but it really worked without to much modifications. About deleting stuff, yeah my bad, I did delete everything to do the pull thing from a clean state.

miguelemosreverte avatar Jul 19 '16 22:07 miguelemosreverte

@iUltimateLP is correct, I managed to modify vertex data like this: paint

by copying the data from a vertex to the one of the vertex below it. Basically you take a brick index, right? Well, then you start counting down from its sides, until you hit bottom. For performance purposes, lets say you stop counting at 100. If the brick is 100 far from the floor next to it, then no modifications would be done.

But if it has a neighbor down below, then it will copy the vertex index that it wants, and paste it onto his own. Now its own vertex, and the one of the neighbor, have the same index, and so the GPU will render them as the same. You are not deleting vertices, just pulling them together. But the result is really satisfying because of Scheidecker use of World Texture Coordinates: They, (the textures) do not stretch, but texture information is procedurally created for them.

This can be used for less blocky mountains or for water surfaces, for when you simulate water with the bricks.

EDIT: Forgot to mention, it was not all roses, I recall having trouble with the normals. Because, sure, you can change vertex info, but remember the normals? Those are cooked so that the face number 6 of the brick, the one that should be facing up and you are forcing it to an angle, point up and reflects, well, what an horizontal surface would! Basically you cannot have it both ways, either you have cooked normal angles or you have dynamic voxel angles.

miguelemosreverte avatar Jul 19 '16 22:07 miguelemosreverte

About UByte4N, how did you end up using that term? It seems like a really low level data structure! But it make sense, since your approach to complex blocks is to, having the same voxel data as before, have more vertices.

I would suggest the opposite. Voxel resolution could allow in the future for, well, more detailed worlds, and if that happen, you could just make high level objects made up of cubes.

But count me in for the trip!

miguelemosreverte avatar Jul 19 '16 22:07 miguelemosreverte

I'm happy someone heard my prayer !

Thank you for your clarifications, I found the UByte4N here: https://github.com/AndrewScheidecker/BrickGame/blob/master/Plugins/BrickGrid/Source/BrickGrid/Private/BrickRenderComponent.cpp#L132

I am new in the amazing world of rendering, and I made the mistake of believing that ubyte4n had no floating point and I learned later that he was normalize by this doc: https://msdn.microsoft.com/en-us/library/windows/desktop/bb322868(v=vs.85).aspx

So for me if I wanted to do more complex shapes I needed more precision and FBrickVertex struct was only allowed to make brick.

I have not fully understood for the voxel resolution, you mean increasing the accuracy of vertex data x, y, z ? I already create my system to determine the type of my brick and get informations like vertex, index, and normals to draw the shapes.

Finally, here is my Skype (mrjackblue) to make some developing session together if you want to.

SirJackblue avatar Jul 19 '16 23:07 SirJackblue

About the voxel resolution I mean that minecraft proposed to use a different kind of voxel type for certain complex shapes, and the opposite would be the way laser scan represent complex shapes, by using a million of voxels. A middle point that will come at some point in the future is where you still have big cubes, but actually they are made up of a grid of smaller cubes, and that is what allows for detail on complex shapes. That way a stair, like the ones in minecraft, is not a special kind of voxel, but an object made up by a combination of them. That is what I mean when I say that at some point in the future more resolution will be available and then this talk of low level vertex tweaking will be out of the window, because you will be happy with the amount of vertices given by the standard blocks.

Now: This is not the present, where visibility of far away blocks and refreshing of their states is still not a trivial problem. So, yes, we will have to copy the already existing solutions out there. And learn about low level vertex manipulation in the process!

miguelemosreverte avatar Jul 19 '16 23:07 miguelemosreverte

You have probably put more thought than me about this vertex problem. So, what are your ideas?

I agree with @iUltimateLP that stairs, for example, just screams Procedural Mesh Component, because as he said, it does not belong to the terrain.

Now terrain, that's another thing. And that I have thought of, and concluded that you do not need extra vertices, but processing power to move them around when LOD says its time to do so.

miguelemosreverte avatar Jul 19 '16 23:07 miguelemosreverte

For me the ideal would be an interface, with differents functions, to know if the type has a complex render. If yes, we override the function which return necessary vertices and indexes. As explained in this post: http://www.blockstory.net/node/59

And after on the rendering loop we check if it's a complex render, if yes we add vertices and indexes, otherwise we draw a simple brick, but I don't think that is as simple as that.

For procedural mesh component, I'm afraid it will be glitchy, that it needs more performance, and the render isn't coherent (procedural mesh is displayed whereas the grid isn't displayed yet) And for the LOD, if we want to save vertices, we can render standard bricks far away, and when the player comes close it renders the correct mesh.

SirJackblue avatar Jul 20 '16 00:07 SirJackblue

Sure. How about this:

Right now, the game sends batches of vertices to the GPU. Those are of a known size. We could add a secondary vertex batch-sender, one that sends batches of exactly the same size, with all the objects that happen to fit inside of it. The render component we know could be renamed as the main grid renderer, and this clone of his, the miscellaneous one.

There are many ideas to talk after this main one is decided, like the priorities of the objects that want to be rendered. But again, no need to talk about that yet.

Over here the objects waiting to be rendered, they all would be complex. Stairs, trees, all static in place and using the voxels system of coordinates.

One last thing, this object, they should have a boolean variable that states whether if not rendered as complex blocks they should not be rendered at all or rendered as normal blocks. This way tree leaves are rendered and complex windows are not so that the hole on the wall is still visible.

miguelemosreverte avatar Jul 20 '16 01:07 miguelemosreverte

What about increase size of batches vertices ?

SirJackblue avatar Jul 20 '16 01:07 SirJackblue

At the end of the day what I am saying is to send, along with the grid data, the objects seen by the player categorized by importance, distance, and complexity, just to name a few. This info would be used alongside the grid data by BrickRenderComponent.cpp after the grid is rendered, and sent to the GPU too, not all but only the amount that can be done without killing the FPS, being the ones chosen and their levels of details thought really well.

miguelemosreverte avatar Jul 20 '16 01:07 miguelemosreverte

About increasing the size of batches, you lose control. My solution adds tons of tweaking room.

miguelemosreverte avatar Jul 20 '16 01:07 miguelemosreverte

But is can be done, what you say. I mean, using a single batch with different data in it would be cleaner. What you do with that extra data is the important part. Making them separate only adds complexity.

miguelemosreverte avatar Jul 20 '16 01:07 miguelemosreverte

So, yeah. Thinking it trough, one big batch, with a separate area for miscellaneous data.

miguelemosreverte avatar Jul 20 '16 01:07 miguelemosreverte

Vertices array on the vertex buffer is a dynamic array, well it doesn't have a limited size, or is there a limitation ?

And because I'm new to rendering, I have no idea how to render all of this :/ If you have any documentation about the subject, don't hesitate to share it !

SirJackblue avatar Jul 20 '16 01:07 SirJackblue

Luckily it truly is not necessary for us mortals to know the insides of the engine.

About the array, is it dynamic? I am going to go check right now.

miguelemosreverte avatar Jul 20 '16 01:07 miguelemosreverte

This should be tested, but for now I have to say that even if TArray supports dynamic array size, the data structure used for the voxels, (Grid>Regions>FInt3 Array of Voxel Indexes), could be really rigid.

But, like I said, if it is a pieceof cake to modify, great. Else, it should not be that hard anyway.

miguelemosreverte avatar Jul 20 '16 01:07 miguelemosreverte

Quick question to get you thinking: The faces for the bricks are hard-coded as 6. 5 is the top, 6 the bottom. 1,2,3,4 the sides. You see how you would have to modify that so that it supports all the amount of faces needed?

miguelemosreverte avatar Jul 20 '16 02:07 miguelemosreverte

For my own project, complex brick can't be bigger than a normal brick. If it's bigger I use mesh/actor, but we can find a solution in a second time :)

And for the face number, I think we can simply add a function (in the IBrickData) which returns the number of faces for each brick render type.

Example: TScriptInterface<IBrickData> BrickData = UBrickRegistery::GetBrickData(BrickMaterial); int32 FacesNumber = BrickData->GetNumberOfFace();

SirJackblue avatar Jul 20 '16 02:07 SirJackblue

Sounds great!

miguelemosreverte avatar Jul 20 '16 02:07 miguelemosreverte

Hey finally finals season ended and now I am going to work on this for a while! I am looking at how minecraft implemented the solution for this problem. Have you done that yet? If so, how did they? Post a link if you have one!

miguelemosreverte avatar Aug 04 '16 03:08 miguelemosreverte

The way I see it to move vertices around or even create new ones there are 3 options, really. option 1 option 2 option 3

That being said, I believe that making a water material that moves the vertices of the blocks makes sense, but doing the same for say, a half block, doesn't seem right, even though is doable.

I would suggest doing like @iUltimateLP , and see how to integrate procedural mesh components with the voxels coordinates transformed to world coordinates as, well, their own world coordinates.

That's what I am going to start doing right now, and @iUltimateLP, if you have something done I would love to check that out.

About minecraft, I believe the translation of the way things work there would be to have an interface, (if the implementation of ProceduralMeshComponent.h is not simple enough) so that each custom object has a constructor function that once called will render the specified object, like a slab of wood, the size of half a block in height.

miguelemosreverte avatar Aug 05 '16 01:08 miguelemosreverte

Talking about achievable things with Procedural Mesh Component, check this out: https://garvinized.com/posts/2016/

I have just found the guy, and I love the step-by-step tutorials. The cool thing is, he uses Procedural Mesh Components right off the bat, which in a way is what Minecraft creator actually did. It helps to avoid this very situation of ours, where we do not see clearly what's the next step is.

Say hello to him from me when you contact him! :)

miguelemosreverte avatar Aug 05 '16 02:08 miguelemosreverte

Hey !

Lastly, I was working on an another module of my game, while still thinking about how to make the voxel module.

If you want some informations on how Minecraft is rendering, this link is nice: http://greyminecraftcoder.blogspot.fr/2014/12/block-rendering-18.html

There is only the main idea, I think in order to understand better how it works, you need to reverse engine with MCP and look at the net.minecraft.client.renderer package.

I'm afraid that using the procedural mesh component, I will lose a lot of performance in comparaison with how BrickGame renders. And I think if we change the struct FBrickVertex there will be a way to gain more freedom to draw shapes.

I would like @AndrewScheidecker's feedback on it.

P.S: For sure, I tell him hello from you when I contact him :)

SirJackblue avatar Aug 07 '16 20:08 SirJackblue

After reading some interesting post, I found my answer for ProceduralMeshComponent performance, I read this answerhub post, with the same question about performance: https://answers.unrealengine.com/questions/412702/procedural-mesh-component-rendering-performance-co.html

Well, at this point BrickGame rendering method is better, and I was thinking how can I improve performance for ProceduralMeshComponent and I found this plugin: https://github.com/Koderz/UE4RuntimeMeshComponent

For me there are 2 possibilties: - Using UE4RuntimeMeshComponent with PolyVox. - Add support for more complexe shape to BrickGame, with a more "heavy" FBrickVertex structure (I don't know yet how to make this :/).

What is your opinion about this ?

Also, making a benchmark of this can be interesting, but I think BrickGame would stay the best way in term of performance.

SirJackblue avatar Aug 08 '16 08:08 SirJackblue

Anything that includes using PolyVox is great. It supports Marching Cubes meshes right off, and is really great abstracting the voxel problem away. Besides it really functions as a gateaway to a lot of tools, because coders that use PolyVox also use other tools and so you end up joining that group. The best example of that are the guys that made a port of Cubiquity to UE4, (which is in Github by the way, supported until 4.8 I believe).

About modifying BrickGame, main problem I find is not the difficulty, but what the correct object-oriented implementation of it. To not make obfuscated code. But that will be solved really fast once the objective is achieved and a pull request is made, because Scheidecker would probably know how to make it look presentable. That is why I had interest on the implementation of Minecraft, because its written in a really object-oriented way. Again, besides that we should just do it and then try to fix it.

Another cool idea if we manage to change BrickGame support of complex voxel shapes, would be to make a branch of BrickGame that uses PolyVox, just like the tutorial link. That way you get the best of both worlds. Or not, because on that implementation PolyVox sends the Mesh ready to be rendered, while on BrickGame thats part of the job of RenderComponent. Yeah I dont think PolyVox has a place inside of BrickGame then, as one of the main features of BrickGame as a Render Plugin is to create the meshes.

About the specifics, the only solution I find is to add empty places on the current data structure, ready to be filled. If not used the usual cubes are rendered, but if used then vertices are created on them. It would indeed be a heavier structure, but its the only way to go. Problem is, that's just supporting the complex blocks. That being done now, what is going to be the way to use that support? Hardcoding? You bet that is going to be the option of choice at the beggining, but after a while it has to be made in a correct object-oriented way just so obfuscation is avoided.

miguelemosreverte avatar Aug 08 '16 13:08 miguelemosreverte

"add empty places on the current data structure, ready to be filled. If not used the usual cubes are rendered, but if used then vertices are created on them" That does not sounds right, and its because until its done there is no way an explanation that short is going to be the real one. So I am going to work on it, see what happens, and come back with results.

miguelemosreverte avatar Aug 08 '16 13:08 miguelemosreverte

Do you want to find a correct object-oriented implementation for Brick data or for rendering or both of them ? For data, Minecraft uses a Registry design pattern with a Block base class, and child class override functions when it's needed. But I think it would be cleaner with an interface like this: http://hastebin.com/epipevopaf.vala

Sorry for my ignorance, I did not really understand the interest to add some empty places in the data structure. Also, I would like to understand what are doing each FChunkVertexFactory, they render the chunk but how ?

In my mind, we iterate through each x,y,z coordinates, get brick data, look at its render rules (opaque, solid, complex), and add vertices and indices, etc.. consequently. And before we change FBrickVertex to draw more complex things.

SirJackblue avatar Aug 08 '16 16:08 SirJackblue