Continuing my tutorial series about voxel-based terrain in Unreal Engine 4, today we’ll be covering voxel generation using the PolyVox and ANL libraries that we setup in the first part of the tutorial. If you haven’t already, I recommend reading the previous article, as it covered getting all of the libraries setup to work with Unreal Engine 4. If you already read the previous part though, let’s continue where we left off.
The AVoxelTerrainActor Class
The first thing we need to do is go into the Unreal Editor and create a new C++ class. Specifically we need to make a new AActor
object to control our voxel terrain generation. I’ve called my class AVoxelTerrainActor
, but you can call yours whatever you want. Once you have the new class created go ahead and open its header file up so we can get started.
The Header (.h) File
There isn’t a whole lot to do here; just a couple of includes and variable declarations really. Let’s start by including the two extra header files we’ll be using.
// Polyvox Includes #include "PolyVox/PagedVolume.h" #include "PolyVox/MaterialDensityPair.h"
The PagedVolume.h
header is the main thing that we’ll be using. It contains information about a special kind of volume included with PolyVox that lets us easily handle loading and unloading voxels from memory. Despite being much better on memory usage than a RawVolume
, this type of volume does have drawbacks. The biggest drawback that a PagedVolume
has is the complete and utter lack of any multi-threading support; you can’t even read voxels from another thread safely! Even with that drawback, the PagedVolume
is a very useful class.
It is possible to prevent locking up the game thread by moving all voxel and mesh generation to another thread to help with performance. I won’t be covering how to do that in this part of the tutorial, however, I plan to do it later in the series. Until we reach that point you should expect voxel generation to lock up the game.
The other header that we’re including defines a few types of voxels for us to use. They’re all based on the MaterialDensityPair
class template, which has two integers that represent the density of a voxel and the material of the same voxel. In this series we’re going to be making Minecraft-like terrain, so having the ability to use both of those variables is a must. The density will be useful for things like water or pressurized areas, which could be used to create underwater caves with air in them.
The Pager Class
Speaking of the PagedVolume
, the next thing we want to create is directly related to using that. The PagedVolume::Pager
class is the one that loads and unloads chunks of voxels from memory. Below is the definition of our custom pager class.
class VoxelTerrainPager : public PolyVox::PagedVolume<PolyVox::MaterialDensityPair44>::Pager { public: // Constructor VoxelTerrainPager(uint32 NoiseSeed = 123, uint32 Octaves = 3, float Frequency = 0.01, float Scale = 32, float Offset = 0, float Height = 64); // Destructor virtual ~VoxelTerrainPager() {}; // PagedVolume::Pager functions virtual void pageIn(const PolyVox::Region& region, PolyVox::PagedVolume<PolyVox::MaterialDensityPair44>::Chunk* pChunk); virtual void pageOut(const PolyVox::Region& region, PolyVox::PagedVolume<PolyVox::MaterialDensityPair44>::Chunk* pChunk); private: // Some variables to control our terrain generator // The seed of our fractal uint32 Seed = 123; // The number of octaves that the noise generator will use uint32 NoiseOctaves = 3; // The frequency of the noise float NoiseFrequency = 0.01; // The scale of the noise. The output of the TerrainFractal is multiplied by this. float NoiseScale = 32; // The offset of the noise. This value is added to the output of the TerrainFractal. float NoiseOffset = 0; // The maximum height of the generated terrain in voxels. NOTE: Changing this will affect where the ground begins! float TerrainHeight = 64; };
This is a relatively simple class; all this class does is override some functions from the base class and declare a bunch of member variables. The member variables will be used to control our terrain generation later on. The most important two lines, however, are these two function overrides:
// PagedVolume::Pager functions virtual void pageIn(const PolyVox::Region& region, PolyVox::PagedVolume<PolyVox::MaterialDensityPair44>::Chunk* pChunk); virtual void pageOut(const PolyVox::Region& region, PolyVox::PagedVolume<PolyVox::MaterialDensityPair44>::Chunk* pChunk);
These two functions are called when a chunk needs to be loaded or unloaded from memory. The pageIn
function is going to be where we spend most of our time in the implementation file, as it is where we’ll be generating our terrain. The pageOut
function isn’t as important, however, you could use it to save the voxels to a file for later use, which can be an extremely important feature to have in some games.
The AVoxelTerrainActor Class
Up next we have the actual Unreal Engine 4 implementation layer. This is another extremely simple class, and most of its members are shared with the Pager.
UCLASS() class VOXELTERRAIN_API AVoxelTerrainActor : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties AVoxelTerrainActor(); // Called after the C++ constructor and after the properties have been initialized. virtual void PostInitializeComponents() override; // Some variables to control our terrain generator // The seed of our fractal UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) int32 Seed; // The number of octaves that the noise generator will use UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) int32 NoiseOctaves; // The frequency of the noise UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) float NoiseFrequency; // The scale of the noise. The output of the TerrainFractal is multiplied by this. UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) float NoiseScale; // The offset of the noise. This value is added to the output of the TerrainFractal. UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) float NoiseOffset; // The maximum height of the generated terrain in voxels. NOTE: Changing this will affect where the ground begins! UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) float TerrainHeight; private: TSharedPtr<PolyVox::PagedVolume<PolyVox::MaterialDensityPair44>> VoxelVolume; };
As you can see it’s a pretty standard Unreal Engine 4 actor. If you’ve used Unreal Engine 4 at all most of what’s happening in this class definition should be extremely familiar, however, there is one member variable that is kind of special and not often seen outside of the engine’s insides. Just in case you’re not familiar with it, let’s go over what it is and why we want to use it.
TSharedPtr<PolyVox::PagedVolume<PolyVox::MaterialDensityPair44>> VoxelVolume;
The above line is declaring the member variable I was talking about a second ago. In UE4 pretty much everything related to memory allocation is handled for you, however, when you’re dealing with classes outside of the engine sometimes you need to handle it yourself. The TSharedPtr
class allows you to have the built-in garbage collector of the engine handle deallocating the variable when nothing is referencing it anymore, which is really helpful when you’re dealing with a pointer to something that multiple classes might be using. That’s about it for the header file, let’s move on to the implementation.
The Implementation (.cpp) File
This file has a bit more going on in it, even though its really not much longer than the header file. First thing’s first, lets get the only new include out of the way.
// PolyVox using namespace PolyVox; // ANL #include "VM/kernel.h" using namespace anl;
You might find yourself asking why I’m including a file called VM/kernel.h
, which is a good question. The short version is that the Accidental Noise Library(ANL) is setup like a virtual machine; you give it a series of instructions, and then it executes them. This setup makes for a pretty easy to use noise library. If you’re interested in specifics about how the library works or a list of available methods, you’re going to need to either read the source code for the library on your own, or wait for the someone to document it. Even if you don’t go read the source code you should have a decent understanding of how the library works by the end of this tutorial, and I will be doing more advanced tutorials using it in the future.
The Constructors
Starting our actual definitions we have two really simple constructors for our classes. These are just defining some defaults for our Actor and Pager classes, so there really isn’t much more to say about them.
AVoxelTerrainActor::AVoxelTerrainActor() { // Default values for our noise control variables. Seed = 123; NoiseOctaves = 3; NoiseFrequency = 0.01f; NoiseScale = 32.f; NoiseOffset = 0.f; TerrainHeight = 64.f; }
VoxelTerrainPager::VoxelTerrainPager(uint32 NoiseSeed, uint32 Octaves, float Frequency, float Scale, float Offset, float Height) : PagedVolume<MaterialDensityPair44>::Pager(), Seed(NoiseSeed), NoiseOctaves(Octaves), NoiseFrequency(Frequency), NoiseScale(Scale), NoiseOffset(Offset), TerrainHeight(Height) { }
The PostInitializeComponents Function
With the constructors out of the way, let’s get the only member function of AVoxelTerrainActor
out of the way. This is the definition of the PostInitializeComponents
function.
// Called after the C++ constructor and after the properties have been initialized. void AVoxelTerrainActor::PostInitializeComponents() { // Initialize our paged volume. VoxelVolume = MakeShareable(new PagedVolume<MaterialDensityPair44>(new VoxelTerrainPager(Seed, NoiseOctaves, NoiseFrequency, NoiseScale, NoiseOffset, TerrainHeight))); // Call the base class's function. Super::PostInitializeComponents(); }
If you haven’t used the Unreal Engine 4 shared pointer implementation before, you’ll likely be unfamiliar with the MakeShareable
function. All this function does is take a pointer and return it wrapped in a TSharedPointer
.
The pageIn and pageOut Functions
Alright we’re finally to the interesting part! Up next we’ve got the functions that actually generate voxels for us. I’m going to give you the full definition first, and then I’ll break it down afterwards. The pageOut
function is empty as you will see, however, we need to define it anyways so the code will compile. It will be useful later on, so don’t think its completely useless just yet.
// Called when a new chunk is paged in // This function will automatically generate our voxel-based terrain from simplex noise void VoxelTerrainPager::pageIn(const PolyVox::Region& region, PagedVolume<MaterialDensityPair44>::Chunk* Chunk) { // This is our kernel. It is responsible for generating our noise. CKernel NoiseKernel; // Commonly used constants auto Zero = NoiseKernel.constant(0); auto One = NoiseKernel.constant(1); auto VerticalHeight = NoiseKernel.constant(TerrainHeight); // Create a gradient on the vertical axis to form our ground plane. auto VerticalGradient = NoiseKernel.divide(NoiseKernel.clamp(NoiseKernel.subtract(VerticalHeight, NoiseKernel.z()), Zero, VerticalHeight), VerticalHeight); // Turn our gradient into two solids that represent the ground and air. This prevents floating terrain from forming later. auto VerticalSelect = NoiseKernel.select(Zero, One, VerticalGradient, NoiseKernel.constant(0.5), Zero); // This is the actual noise generator we'll be using. // In this case I've gone with a simple fBm generator, which will create terrain that looks like smooth, rolling hills. auto TerrainFractal = NoiseKernel.simplefBm(BasisTypes::BASIS_SIMPLEX, InterpolationTypes::INTERP_LINEAR, NoiseOctaves, NoiseFrequency, Seed); // Scale and offset the generated noise value. // Scaling the noise makes the features bigger or smaller, and offsetting it will move the terrain up and down. auto TerrainScale = NoiseKernel.scaleOffset(TerrainFractal, NoiseScale, NoiseOffset); // Setting the Z scale of the fractal to 0 will effectively turn the fractal into a heightmap. auto TerrainZScale = NoiseKernel.scaleZ(TerrainScale, Zero); // Finally, apply the Z offset we just calculated from the fractal to our ground plane. auto PerturbGradient = NoiseKernel.translateZ(VerticalSelect, TerrainZScale); CNoiseExecutor TerrainExecutor(NoiseKernel); // Now that we have our noise setup, let's loop over our chunk and apply it. for (int x = region.getLowerX(); x <= region.getUpperX(); x++) { for (int y = region.getLowerY(); y <= region.getUpperY(); y++) { for (int z = region.getLowerZ(); z <= region.getUpperZ(); z++) { // Evaluate the noise auto EvaluatedNoise = TerrainExecutor.evaluateScalar(x, y, z, PerturbGradient); MaterialDensityPair44 Voxel; bool bSolid = EvaluatedNoise > 0.5; Voxel.setDensity(bSolid ? 255 : 0); Voxel.setMaterial(bSolid ? 1 : 0); // Voxel position within a chunk always start from zero. So if a chunk represents region (4, 8, 12) to (11, 19, 15) // then the valid chunk voxels are from (0, 0, 0) to (7, 11, 3). Hence we subtract the lower corner position of the // region from the volume space position in order to get the chunk space position. Chunk->setVoxel(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), Voxel); } } } } // Called when a chunk is paged out void VoxelTerrainPager::pageOut(const PolyVox::Region& region, PagedVolume<MaterialDensityPair44>::Chunk* Chunk) { }
Starting with the first variable defined in the function, we have the CKernel
.
// This is our kernel. It is responsible for generating our noise. CKernel NoiseKernel;
This is the single most important class in the ANL code. It is the one that lets you build the instruction tree for the VM, and therefore it is also the one that lets you generate noise. In this tutorial we won’t be covering every function it has to offer, however, that doesn’t make it any less important.
The next thing you’ll find in the function are a couple of “constants”.
// Commonly used constants auto Zero = NoiseKernel.constant(0); auto One = NoiseKernel.constant(1); auto VerticalHeight = NoiseKernel.constant(TerrainHeight);
At first glance you might think doing this is a little bit odd; I certainly thought it was when I first used this version of the library. Almost every function in the CKernel
class uses the CInstructionIndex
class for their parameters instead of floats or integers, and likewise almost all of them return another CInstructionIndex
that can be fed into another function. I’m defining any constants that are used more than once before using them, not only because it reduces clutter, but because it results in less instructions overall.
Moving on though, we’re starting to get into the actual generation now.
// Create a gradient on the vertical axis to form our ground plane. auto VerticalGradient = NoiseKernel.divide(NoiseKernel.clamp(NoiseKernel.subtract(VerticalHeight, NoiseKernel.z()), Zero, VerticalHeight), VerticalHeight);
The VM-like structure of the noise library makes this line look far more complicated than it actually is. As the comment above it says, all it does is create a gradient to serve as the ground plane. To rewrite it in a simpler looking way using normal operators though, it could really look like this instead: FMath::Clamp(VerticalHeight - Z, 0, VerticalHeight) / VerticalHeight;
The next line runs a simple select operation on the gradient we just made.
// Turn our gradient into two solids that represent the ground and air. This prevents floating terrain from forming later. auto VerticalSelect = NoiseKernel.select(Zero, One, VerticalGradient, NoiseKernel.constant(0.5), Zero);
I think the comment conveys what this does fairly well, however, if you’re wondering what this is doing it’s pretty simple. It is equivalent to an if statement like this:
if (VerticalGradient > 0.5) return 1; else return 0;
Fairly simple right? In reality the function itself is more complicated than that, however, for how we’re using it that’s pretty much all it does. Let’s continue with our tour of the function, the next thing we find is the noise generation instruction.
// This is the actual noise generator we'll be using. // In this case I've gone with a simple fBm generator, which will create terrain that looks like smooth, rolling hills. auto TerrainFractal = NoiseKernel.simplefBm(BasisTypes::BASIS_SIMPLEX, InterpolationTypes::INTERP_LINEAR, NoiseOctaves, NoiseFrequency, Seed);
Here we’re using one of the simplified fractal functions to create an fBm basis for our noise generation. This type of noise is great when you’re trying to make plains and relatively smooth terrain, however, it can fall short when you’re trying to make mountains and other jagged terrain features. For the purposes of this tutorial series though this will be a great start. Below is an example of the kind of terrain this will produce.
If you want to experiment there are several other functions you can use here, however, you won’t be able to test your changes until you have a way to render the voxels. The next part of this tutorial will cover rendering the voxels, so you’ll be able to try it out once that is finished. Here is a list of other functions you can use anyways though
- NoiseKernel.SimpleBillow
- NoiseKernel.SimpleBillowLayer
- NoiseKernel.SimpleRidgedLayer
- NoiseKernel.SimpleRidgedMultiFractal
It should be noted that some of these functions have extra arguments that you can experiment with, however, besides the extra arguments you can add you should be able to swap them out with no problem. Continuing with our walk through the pageIn
function, we have some terrain scaling code.
// Scale and offset the generated noise value. // Scaling the noise makes the features bigger or smaller, and offsetting it will move the terrain up and down. auto TerrainScale = NoiseKernel.scaleOffset(TerrainFractal, NoiseScale, NoiseOffset);
Scaling noise works just about as you would expect, it multiplies the output by the scale parameter. Offsetting it is a similar thing, however, it uses addition instead of multiplication. Scaling the terrain will make the features larger or smaller, while offsetting the terrain will move it up and down. The second-to-last instruction we give the kernel just fixes up some odd things that can happen during noise generation.
// Setting the Z scale of the fractal to 0 will effectively turn the fractal into a heightmap. auto TerrainZScale = NoiseKernel.scaleZ(TerrainScale, Zero);
By turning the fractal into a height map we can avoid floating islands of terrain being generated. Doing this makes us lose some terrain features, however, they can be added back in by using additional noise functions. Moving on we have the final instruction for our noise kernel, which just applies the height offset to the ground plane we made earlier.
// Finally, apply the Z offset we just calculated from the fractal to our ground plane. auto PerturbGradient = NoiseKernel.translateZ(VerticalSelect, TerrainZScale);
This is another extremely simple instruction, all it does is add the result of the second instruction to the Z position that gets passed to the first instruction. This moves the ground plane up and down by the value of the noise, forming hills and other terrain features. Now that we’ve finished with all of the instructions, all that’s left is to apply them to our voxel volume. To do that we need a CNoiseExecutor
and a couple of nested for-loops as you can see below.
CNoiseExecutor TerrainExecutor(NoiseKernel); // Now that we have our noise setup, let's loop over our chunk and apply it. for (int x = region.getLowerX(); x <= region.getUpperX(); x++) { for (int y = region.getLowerY(); y <= region.getUpperY(); y++) { for (int z = region.getLowerZ(); z <= region.getUpperZ(); z++) { // Evaluate the noise auto EvaluatedNoise = TerrainExecutor.evaluateScalar(x, y, z, PerturbGradient); MaterialDensityPair44 Voxel; bool bSolid = EvaluatedNoise > 0.5; Voxel.setDensity(bSolid ? 255 : 0); Voxel.setMaterial(bSolid ? 1 : 0); // Voxel position within a chunk always start from zero. So if a chunk represents region (4, 8, 12) to (11, 19, 15) // then the valid chunk voxels are from (0, 0, 0) to (7, 11, 3). Hence we subtract the lower corner position of the // region from the volume space position in order to get the chunk space position. Chunk->setVoxel(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), Voxel); } } }
This code snippet evaluates our instructions for every voxel in the chunk and decides if the voxel is solid or not before saving the data to the chunk. As I mentioned previously, we’re using the MaterialDensityPair44
type that comes with PolyVox, which allows us to have up to 256 materials with values 0-255 and 256 density levels, again with values 0-255. While the number of materials is a tad on the limited side, we won’t be using any more than a handful of them during this tutorial. In the above example we are only allowing for two materials and densities, solid or not-solid. It is possible to expand the number of bits allocated for materials or density, however, unless you’re making an extremely complicated game you probably won’t need to do so.
// Evaluate the noise auto EvaluatedNoise = TerrainExecutor.evaluateScalar(x, y, z, PerturbGradient);
An important note about the evaluateScalar
function is that the last parameter is the CInstructionIndex
that you want to evaluate the instruction tree from. Normally that should be the last instruction that you created, however, for debugging purposes it can be useful to set it to something else. For example, you could have it output only the fBm noise to try and visualize what that looks like directly. Once you have this function implemented, you should be able to compile your project without any errors; provided I haven’t missed anything you needed to compile it.
That wraps up this part of the tutorial. This part was quite long, and the next part is going to be even longer. Up next we need to cover rendering our voxels so we can actually use them in-game. I hope this was useful to you, and if you feel like I did a good job on this or I forgot something please let me know in the comments.
This is very helpful! Thank you!
I think you have a typo in the Pager header file.
// PagedVolume::Pager functions
virtual void pageIn(const PolyVox::Region> region, …);
virtual void pageOut(const PolyVox::Region> region, …);
should be
virtual void pageIn(const PolyVox::Region* region, …);
virtual void pageOut(const PolyVox::Region* region, …);
?
Sorry, & not *:
virtual void pageIn(const PolyVox::Region& region, …);
virtual void pageOut(const PolyVox::Region& region, …);
Hello, It’s a wonderful project ! But as a new to unreal engine , I don’t know how to generate a map like this even if I finish all 5 parts. Should I just drag the c++ class into the map or something else? After just drag the component in, the editor will crash after click playing.
Dragging the C++ class into the map is the correct thing to do. Could you get me a stack trace for one of the crashes you’re experiencing? There is a common crash that seems to be a bug in 4.12, but I’m not sure of the cause at this time. I believe that it is an engine issue and is only being made more common by something that I have done in the voxel terrain project, as I have experienced the crashes in other projects.
Here is a stack trace of the crash, I’ve been trying to work out what is causing it as well. So far I’ve had no luck.
Access violation – code c0000005 (first/second chance not available)
UE4Editor_PlaygroundProject_4827!VoxelTerrainPager::pageIn() [d:\UE\projects\unrealengine\playgroundproject\source\playgroundproject\avoxelterrainactor.cpp:70]
UE4Editor_PlaygroundProject_4827!PolyVox::PagedVolume<PolyVox::MaterialDensityPair >::Chunk::Chunk() [d:\UE\projects\unrealengine\playgroundproject\thirdparty\polyvox\include\polyvox\pagedvolumechunk.inl:65]
UE4Editor_PlaygroundProject_4827!PolyVox::PagedVolume<PolyVox::MaterialDensityPair >::getChunk() [d:\UE\projects\unrealengine\playgroundproject\thirdparty\polyvox\include\polyvox\pagedvolume.inl:281]
UE4Editor_PlaygroundProject_4827!PolyVox::PagedVolume<PolyVox::MaterialDensityPair >::Sampler::setPosition() [d:\UE\projects\unrealengine\playgroundproject\thirdparty\polyvox\include\polyvox\pagedvolumesampler.inl:93]
UE4Editor_PlaygroundProject_4827!PolyVox::extractCubicMeshCustom<PolyVox::PagedVolume<PolyVox::MaterialDensityPair >,PolyVox::Mesh<PolyVox::CubicVertex<PolyVox::MaterialDensityPair >,unsigned int>,PolyVox::DefaultIsQuadNeed() [d:\UE\projects\unrealengine\playgroundproject\thirdparty\polyvox\include\polyvox\cubicsurfaceextractor.inl:309]
UE4Editor_PlaygroundProject_4827!PolyVox::extractCubicMesh<PolyVox::PagedVolume<PolyVox::MaterialDensityPair >,PolyVox::DefaultIsQuadNeeded<PolyVox::MaterialDensityPair > >() [d:\UE\projects\unrealengine\playgroundproject\thirdparty\polyvox\include\polyvox\cubicsurfaceextractor.inl:248]
UE4Editor_PlaygroundProject_4827!AAVoxelTerrainActor::BeginPlay() [d:\UE\projects\unrealengine\playgroundproject\source\playgroundproject\avoxelterrainactor.cpp:106]
UE4Editor_Engine!AWorldSettings::NotifyBeginPlay() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\worldsettings.cpp:164]
UE4Editor_Engine!AGameMode::HandleMatchHasStarted() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gamemode.cpp:623]
UE4Editor_Engine!AGameMode::SetMatchState() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gamemode.cpp:733]
UE4Editor_Engine!AGameMode::StartMatch() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gamemode.cpp:600]
UE4Editor_Engine!UWorld::BeginPlay() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\world.cpp:3218]
UE4Editor_Engine!UGameInstance::StartPIEGameInstance() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\engine\private\gameinstance.cpp:293]
UE4Editor_UnrealEd!UEditorEngine::CreatePIEGameInstance() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\playlevel.cpp:3250]
UE4Editor_UnrealEd!UEditorEngine::PlayInEditor() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\playlevel.cpp:2346]
UE4Editor_UnrealEd!UEditorEngine::StartQueuedPlayMapRequest() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\playlevel.cpp:1103]
UE4Editor_UnrealEd!UEditorEngine::Tick() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\editorengine.cpp:1246]
UE4Editor_UnrealEd!UUnrealEdEngine::Tick() [d:\build\++ue4+release-4.12+compile\sync\engine\source\editor\unrealed\private\unrealedengine.cpp:368]
UE4Editor!FEngineLoop::Tick() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:2775]
UE4Editor!GuardedMain() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\launch.cpp:148]
UE4Editor!GuardedMainWrapper() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
UE4Editor!WinMain() [d:\build\++ue4+release-4.12+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:200]
UE4Editor!__scrt_common_main_seh() [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:264]
kernel32
ntdll
0x00007FFCD87F9152 (UE4Editor-Core.dll)处(位于 UE4Editor.exe 中)引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突。
I don’t know if i found the right thing
Can someone clarify where Voxel with methods (setDensity and setMaterial) is being defined ?
My bad. Should pay more attention to code comments.
how did you fix it?
lol the codes jump up to the comment above
I’m really struggling with the linking of the headers. I completed last part successfully but it says it still can’t find the 2 header files of polyvox. Code is all the same. Did I save the Actor class in the wrong location or something?
Hello, first thank you for that nice tutorial. It’s very nice to read!
I am trying to implement it on UE 4.13 on OS X. Using XCode to compile the source code. I compiled the ANL and now I am trying to include the “VM/kernel.h” and want to use the library. I am getting the error
Unreal Projects/RTSGame/ThirdParty/accidental-noise-library/VM/../vectortypes.h:14:21: error: field ‘a’ is uninitialized when used here [-Werror,-Wuninitialized]
though. The code responsible for the error is
SRGBA(int al) : r(a), g(a), b(a), a(al) {}
If you have any idea how I can solve this issue, I would be very grateful!
Thanks in advance!
Everything is fine but I get 2 errors. Although I have included all header files, The Compiler doesn’t know what “Voxel” or “bSolid” is. They are both undefined. Can someone help me out?
Nevermind…I really ought to read comments carefully
Awesome tutorial bro I got everytrhing working. Question, How would I go about making a spherecal voxel globe rather than a flat terrain?
Thanks a ton for the tutorial, it’s great.
I’m a bit stuck though towards the end. Not sure what’s going on but I don’t seem to have the following functions:
region.getLowerX() and it’s variants.
Presumably these would be defined in PolyVox but there doesn’t seem to be any trace of them. And I can’t see any mention of them being defined in what we’re doing here.
If anyone can advise it would be VERY much appreciated!!
Are you sure you have switched to the develop branch of PolyVox? Not sure if this is the problem, but afaik it is a bit more ahead than the master branch.
For some reason when i try to include the polyvox headers it can’t find them.
hello, sorry for the late reply, sometime with UE4 when you include external lib you need to compil with the editor not with visual, or else it wont detect the files.
i’m still searching for a solution to this problem, it’s prettry annoying to not have auto-completion on my visual studio with this, if anyone know a way to repair that i’m listening 🙂
easy answer my bad, just need to go in your project and right click on your .uproject and do generate visual studio files