Hello and welcome back to codeplace it’s been a while since i last uploaded a video regarding voxels and this one is pretty long due that’s adding texturing support to our 3d machine and this would work with our knife meshing also so as far as matching cubes is concerned That implementation is a bit more complicated on the shader side and i’m not that well versed with it so bear with me that will take some time as i figure it out but today we will be focusing on adding textures to our greedy machine and later On in this video as usual we’ll be going over some github suggestions and issues and at the end we’ll be having a discussion regarding what would be the correct way to handle our message in a proper voxel system and how could you optimize it and take more control over your mesh buffers basically So let’s get started i’m going to tell you a story about how i went about deciding which approach to use for texturing so this is around the time well during my second implementation of a voxel engine in unity at the time i only knew one solution for texturing that was using Texture atlases and i pretty much thought minecraft and other such games also use texture act listing and it’s pretty simple also right you have one big texture with all your block textures and you just extract the piece and apply it to the uh whatever mesh you’re creating now texture atlassing works very well With a knife meshing because all your faces are of the same size right it’s everything is a square so you can easily take like assign the correct uvs to each square and you can extract that texture from that lesson applied and it works pretty well but the problem is when you start uh Going into greedy machine right so in 3d meshing i think i change this to Wireframe so you know our faces are of irregular sizes some are squares some are rectangles and they need not be of the same units also right so three by three squares are there and then three by four square rectangles so on so that makes it really difficult to implement text shared blessing But texture addressing can still be done but it would be very complicated so you’ll have to have two uv channels one which will denote the actual texture coordinates in your texture atlas and that one uv channel would uh denote the scale so you will take out the texture atlas and then scale it But the problem then comes is you will have to do the repeating of the texture atlas over the area yourself and it just makes the shade a bit more complicated but there’s a pretty simple approach to texturing uh or you could consider it as an alternative to text atlases and in most Of the cases it would be better that’s using a texture array so what texture atlas does is it packs all your texture in one texture file and you can then index it or you can basically query the texture atlas right in case of texture array you basically get an array of textures And then you you can use an array index to get whatever you want so if i want to place a grass texture and suppose the texture in the texture array the grass texture is at index three i can just pass the three dimensional uv channel Xyz and z would be used as the index to query the texture array and texture is a concept that’s pretty prevalent in graphics programming i think uh you’ll find it everywhere in unity unreal engine and even an opel gl so texture array works really nicely with uh your greedy meshing you’ll see with So less effort we’ll be able to implement or add textures to our meshes so now enough of the theory part let’s get started with the implementation okay so if you see the materials folder for the project i have created a new folder called textures and in this i have imported a few Textures for like the dirt blocks grass blocks and the stone blocks and these textures come from the kenny’s voxel pack i mean you can use your own textures also but i think this is a great pack to get started so i’ll leave a link down below and Do check it out there are a lot more great assets by kenny i think everybody knows him by now so we’ll be using this texture pack and we’re not using all the textures i mean you can go ahead and set up all of them but for demonstration purposes these four are fine okay So now that we have a textures how do we go about creating a texture array so that basically we need to pass that texture array to the material now in unreal engine it’s pretty simple there’s actually an asset type for textured days if you go here you’ll see a textured 2d array You can just select this we’ll just call it voxel texture today and once you open this you can basically add your textures here in the source 2d so you see we have a source textures array here so we need four elements here and we’ll select our textures accordingly so dirt and stone okay Now this indexes also matter so as we’ll be populating our vertex buffers and we’ll be populating our uv channels we’ll be setting up these indexes also in our buffers so depending upon the block type and the normal direction we’ll either set the index to zero one two or three so Now that we have a texture is set up let’s do the code side changes and then we’ll look at the material setup required now before we start with the implementation there’s actually a issue in our current implementation for 3d machine and that is regarding uvs so till now it wasn’t prevalent since we Were not doing any texturing or anything but if we take the current uv setup and apply the textures some of those textures will be rotated okay and there have been github issues regarding them okay two people pointed it out and if you actually look at the code it’s pretty understandable why this happens And that is because our triangle’s order isn’t fixed it depends on the normals so if a triangle order changes that’s basically the way in which the face is going to be rendered or the vertex connections will change right so the order of the face is changing Basically so in that case our uv order should also change so that’s why there are cases in which the textures appeared flipped and we’ll be fixing that going ahead uh because considering the normal and the access along which the current phase is being generated we need to set the different uvs But right now the fix i’ll be providing right now is kind of a small fix only uh because i believe there would be a better way to handle this situation right uh like for triangles without if else we were able to generate the correct triangle order by just adding and Subtracting the normal value but all we need to do now is just let it get it working and maybe we’ll refactor it further down the road to make it more sensible and readable okay so onwards to our implementation uh i’ll go to our header class uh greedy chunk And we’ll be adding a new method here that will decide what would be the texture index for the current phase being generated okay so let’s call it end get texture index and this would take in a block so what is the current block that’s being worked upon and it will also take The normal so with this we’ll be able to see along which direction the face is being generated because for the glass block uh the top face has a different texture and the side faces have a different texture and also the bottom face would have a different texture right but So we need the normal value here and if in your engine you need some other values also just have a utility method that you’ll be able to generate the correct texture index okay we’ll take an f vector here that would be the normal okay this will be a const method so Let’s go ahead and create the implementation point generate definition okay so it will be a simple switch case uh nothing much but before going ahead uh uh let’s talk about how we would be passing this uh texture index to our material so right now we are using the procedural mesh component so We are pretty much bound to the mesh buffers defined at that component we can’t create our own buffers or change the layout and size of those buffers so we would have to repurpose few things here so like uh we can repurpose the color channel right you we can use the Alpha value to set the index and we can also pass in the uvs here using the other channels or we can use the uv 0 and use the first channel of uv 1 to pass the index so you have limited possibilities here right you’ll need to repurpose one of these channels To pass whatever you want so for now i’ll be going with the color alpha since in future if we do an implementation regarding ambient occlusion we’ll be needing the color channel for something else so let’s get started with that let’s start by implementing the get Texture and this is going to be a simple switch case only and if you have a lot of blocks certainly the switch case would grow and i don’t see a way around that unless you configure it in some way but i think it’s fair light it’s just a one-time setup required So we’ll create this block here and next we’ll add the empty cases also this is generated in that case that’s pretty weird generate the other cases also but i’ll just copy it out then okay and we’ll have one more case here so if normal equals the down vector in that case We’ll return the dirt block only so f vector down vector so we’ll return so this indexes here are basically the same as what we have in our texture array so zero is the top grasp texture one is the side grass texture 2 is the dirt texture and 3 is the stone texture And in default case we can return to 55 and the reason we are returning 255 is because uh the channel we are using it right so f colors alpha channel we are using and each of this component is a byte so to unsign byte basically so we can have 255 values in here now you could say that that’s a limiting thing that you can only have 255 different textures and you’d be absolutely correct so other ways to do this would be to use the any of the uv channels to pass this or something is to use a custom mesh component itself That we’ll be discussing later on at the end of this video so for now let’s just focus on the implementation of this right now that we have our method to get the texture index let’s pass it using our color channel so we’ll set all of these to zero and just call Get texture index here get texture okay and to this we’ll need to pass the block that is available as part of the mask and the normal that we have computed right here okay now that our extra index is going inside the material we need to set up the correct values for our uv Okay so as i said below this would be kind of a workaround fix and just copy paste it here so depending upon our normal value like if the normal is across x axis uh the uv or there is this otherwise it’s using the existing uv order okay So ideally across each of the axis the uv order would be different but it’s only the x axis that really matters toward z axis uh whatever is this order right this order fits right for the z axis and for the y axis uh it doesn’t really Matter right since y is the top view so and if it even if it’s rotated it doesn’t matter but if you’re going for a perfect scenario right depending upon the normal axis you’ll have to put a different uv order okay so this code right here is fine and Actually that’s all you need to implement texture is from the coding point of view next we’ll implement the material that will consume this data and apply the correct texture so let’s go ahead and create a new material here we’ll just call it textured and we’ll open it up and We basically need few things here and we can copy some parameters from the previous material the vertex color as you’ll basically be reusing those okay so these parameters the metallic can go in the metallic circularity and the roughness next we will also need the vertex color here so we will get that and We need another parameter for our vertex or texture array that comes under parameters and here you will have a texture sample parameter 2d array okay and we can just name it texture array okay so we can go in our parameter and set the default value for this and this Would be the voxel texture 2d array okay now to sample this we need a three-dimensional uv coordinate here and we can just pass in the base color here so it says here also right the 2d sample array needs a uvw input so basically a three-dimensional texture coordinator So we’ll go here and create the texture coordinate node xcode 0 right and to this we need to append the alpha value okay now again back to our code uh one thing i didn’t mention is uh in our texture coordinates we are passing the height and width so this height and width will Allow us to repeat the texture across the face right so that the texture doesn’t appear stretched okay back in here and so we’ll take the alpha channel and another thing to note here is the vertex color here is normalized so it won’t be between 0 and the Max byte value it will be between 0 and 1. so what we’ll need to do here is multiply this okay and we’ll multiply this by a constant and let’s name put the value to 55 okay next we’ll round this off just so that so because we want an integer as our Index right so we’ll round it off and we’ll take this texture coordinate and append to it okay this value and we’ll pass this in the uvw so this append will transform this two-dimensional texture coordinate to a three-dimensional value and you’ll start seeing here that we are seeing something right uh we are seeing The stone texture here so that’s all that’s required for the material setup right we can now just save this and apply it to our greedy meshing blueprint and see how it looks so with this save uh we’ll create a material instance also so that we can modify our properties Without actually needing to recompile okay so the flat material instance we have created so you see all our properties are visible here and we go to our main world and we’ll change the material to textured flag now if i play the game it should probably work otherwise we’ll see if there are any Issues okay so it’s working and we just have stone blocks everywhere i think we’ll need to modify the generation but at least you can see the texture arrays are working okay so let’s change it to a 2d world okay and generate and see right so this is also just stone blocks everywhere So what we’ll do now is uh modify the height map algorithm ah the way our blocks are generated so that we are getting different values uh the grass blocks also in such cases because if you see the current uh 2d hype map generation right general 2d height map we either add the stone Block or the a block so let’s modify this to actually add some different blocks also so that we can see the profound effect of our texturing system so i modified this and what i have here is pretty simple so once we get our height value right we iterate over the z axis so If the height is less if the current value is less than three of height right height minus three we can set it stone blocks so everything up till height minus three would be stone blocks then from height minus three to height minus one would be dot blocks and if it’s equal to height Minus one that’s like the top layer that would be the grass blocks and anything else we’ll put it as the air block so now it’s up to you how you want to populate your actual voxel data or the blocks array and you can put all different kinds of blocks here and Depending upon these values the values will be picked up in the engine by the material and the correct texture would be displayed so let’s compile this okay one action with one process and it’s done right so we play now we should see the grass blocks at top and then the dirt blocks And so on let’s play and you see we have the grass blocks on top and if we go to the side you’ll see what i meant by that so we have the stone blocks then a layer of dirt blocks and finally the grass blocks and that’s pretty prevalent also so we Okay i think i broke my voxel editing or it doesn’t work in the negative chunks so i’ll take a look at that there’s as i mentioned in the last episode also there are some issues with those implementations that i need to clean up but you see here right as we go down we See stone blocks and this right here is a grass block right so the bottom face of the grass block is also a dirt block so this is basically how you would add textures to your greedy meshing algorithm and you can use the same approach for your knife meshing also and even the texture Atlas method would work but the major benefit of using texture arrays is you can actually reduce the number of size because you just need three components but as for texture atlases you’ll need four components right because uh you you will need a uv value for the actual Texture to pick from the atlas and the uv value for the scale of that texture so you could say the index for a texture atlas is a two dimensional component but for the texture array you can just pass in the index as one dimension so you save some performance there and Also there could be some artifacts in the boundaries of texture atlases because once you sample at the boundaries there could be some bleeding with the adjacent textures uh one way to fix that is to by have some padding in between them but even those paddings can lead to artifacts so By using texture arrays you can avoid those artifacts okay so i hope you like this implementation it’s pretty simple and with just few changes we are utilizing the engine and the material system to create as many textures as we want in our 3d machine so now we’ll go over some suggestions and Issues from github and i’ll talk about the limitations with the current procedure mesh component so now that we have our chunks textured uh i really wanted to go over this chunk material suggestion that i got on our github page so what this would allow us to set multiple Materials on the chunk right right now we can only set one material and why would we need multiple materials so by having multiple materials we can have some blocks shaded in a different way like you have what water blocks and you need some vertex displacements in that or Some other kind of effects you need for particular blocks like you have a light block that does some emission shade effects right so by having the ability to assign multiple materials we can achieve that pretty simply and this suggestion also talks about a very simple approach to achieve That uh and thanks to aldrio i don’t know if i’m pronouncing that right so pardon me for that but what this implementation is suggesting is uh basically to utilize the create mesh section right so right now we are just creating one mesh section and you can actually set different material per mesh section Okay so when creating the face depending upon the block we can change to which mesh section the current vertex would be added right and by using that we can create different mesh sections so we can have one mesh section for our texture array material we can have a different Mesh section for our water blocks because water blocks would have a different uh material altogether right so using this we’ll be able to assign multiple materials and we’ll be able to create lots of interesting shade effects and without modifying much of our actual mesh generation code right because your Mesh generation happens only once it’s just that you get different mesh sections out of that mesh generation rather than just one section and each of those section can have a different material so i’ll link uh i’ll put a link down below to this uh suggestion also uh go Through it if you want to implement it right now uh we’ll be implementing this when we actually start dealing with transparent uh textures and transparent blocks like water blocks okay so this is one of the suggestions that i found pretty elegant to be honest uh because even i was considering to do something Like this for uh for the unity implementation that i’m creating which soon is going to be an open source library so stay tuned for that but uh i had a pretty different idea like to create different measures altogether but so that would require multiple runs of the 3d meshing algorithm which is not Performant at all but this solution right here with just one run of the algorithm we can get separate meshes okay so really like this suggestion and finally coming to the second limitation that we have right now in our current system that is that we are locked to the predefined vertex buffers or the Channels that exist with the procedural mesh component right we have the color channel and four uv channels and we can’t even change the layouts or sizes so ideally these channels should be enough like to get most of your effects right you can repurpose the uv channels to Pass some other data they need not be just uv stuff okay we can pass the texture index also in one of the uv channels or we can pass the ambient occlusion big damp occlusion values also so that will keep it simple but if you want full control over your uh mesh buffers And that full control would allow for more optimizations also right you will be able to optimize the buffer channel so that you can essentially minimize the amount of data that’s passed to the gpu and unreal engine actually allows you to do that uh using a concept called f vertex factory and Uh like the documentation on this isn’t pretty great but i found this great medium article which talks about this so what fm vertex factory would allow you to do is create a custom mesh component right and what this custom mesh component allows you to do is define your vertex buffers your Layouts and sizes for those buffers and you will get complete control over that and also how they are passed to the shaders but all this control comes at a cost like these shaders i don’t think you can use the existing material system you’ll have to manually write the shaders for your Custom mesh components and as an example implementation if you look at the static mesh component or the procedural mesh component these components itself use the vertex factory to build themselves out so i’ll link i’ll put a link down below to this vertex factory guide also and it’s a pretty pretty complicated thing right I don’t think i’ll be covering this in this tutorial series because there’s a lot of things that you need to define to get this working as will be basically working with the vertex level or the pretty low graphic level thing here right you’ll be directly interacting with vertex buffers So it’s pretty low like your opengl or directx level thing you’ll be doing but at least those will be abstracted you won’t be writing directx buffers or opengl buffers right that abstraction would be there but uh another thing that i found complicated is like we’ll have to create our own factory shaders I’m not sure if they could be used with the existing material system or will have to type out our own shaders manually but this is something that would help you to get rid of that limitation so if you have exhausted all your available channels in the procedural mesh component and you Still need to pass more data this is the way going forward right and if you are really creating a production level engine i would suggest look into this and you’ll be able to optimize your mesh data with full control so that’s all for this episode uh we have completed what we Sought out to do uh we have implemented the textures for a greedy meshing and you can mirror over the same implementation to knife meshing but i don’t think anybody would be using naive machines so i’m not focusing on implementing that anymore right but if you want you can it’s Pretty simple to do that and one thing we found out there is a bug with our uh runtime code to the runtime editing of blocks and if you have already have a solution please do leave a full request i’ll be happy to accept that or i’ll fix it between the episodes and We’ll can talk about that in the next episode so that brings me uh what you would like to see next right we could start over the baked ambient occlusion effect as i think that adds pretty nice uh details to our meshes or we can go over some other meshing algorithms That is something that i’ll need to research or we can advance our marching cube implementation also right uh we don’t have runtime modification capabilities in that nor do we have texture support so any of these topics uh leave them down below in the comments what you would like to see and I’ll be happy to create a tutorial on that and if you have any other suggestions feel free to leave them here or on the github page or if you have any contributions to make feel free to do that and like the video share the video with the Friends it really helps the channel out and subscribe for the upcoming content thank you Video Information
This video, titled ‘UE5 C++Tutorial – Minecraft like Voxel Terrain Generation : Part 7 Textures And Materials’, was uploaded by CodeBlaze on 2022-08-05 13:30:14. It has garnered 4448 views and 73 likes. The duration of the video is 00:30:17 or 1817 seconds.
UE5 Source Code – https://github.com/BLaZeKiLL/UE5VoxelTutorial UE4 Source Code – https://github.com/BLaZeKiLL/UE4VoxelTutorial
Texture Assets – https://www.kenney.nl/assets/voxel-pack Material System – https://github.com/BLaZeKiLL/UE5VoxelTutorial/issues/14 Vertex Factory Guide – https://medium.com/realities-io/creating-a-custom-mesh-component-in-ue4-part-1-an-in-depth-explanation-of-vertex-factories-4a6fd9fd58f2
Find me on GitHub – https://github.com/BLaZeKiLL Follow me on Twitter – https://twitter.com/CodeBlazeIO Follow me on Reddit – https://www.reddit.com/user/X-CodeBlaze-X Follow me on Instagram – https://www.instagram.com/code.blaze/
00:00 – Introduction 00:56 – Theory 04:04 – Texture Array Setup 06:03 – Code Definition 10:14 – Code Implementation 14:09 – Material Creation 18:48 – Height Map Changes 22:18 – Github Suggestions 28:36 – Outro
#indie #gamedevelopment #programming #unrealengine #minecraft #voxel