Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Fill out your copyright notice in the Description page of Project Settings.
- #include "tw_GARVINIZED.h"
- #include "FNoiseWorker.h"
- // PolyVox
- #include "PolyVox/CubicSurfaceExtractor.h"
- #include "PolyVox/Mesh.h"
- using namespace PolyVox;
- // ANL
- #include "VM/kernel.h"
- //using namespace anl;
- typedef anl::CInstructionIndex Cii;
- class FNoiseWorker::PrivateData {
- public:
- anl::CKernel NoiseKernel;
- Cii* PerturbGradient;
- Cii* GrassZ;
- Cii* OreFractal;
- anl::CNoiseExecutor* TerrainExecutor;
- PrivateData(const VTPagerDetails& vtPagerDetails) :
- TerrainExecutor(nullptr)
- {
- // Commonly used constants
- auto Zero = NoiseKernel.constant(0);
- Cii One = NoiseKernel.constant(1);
- Cii zScale = NoiseKernel.constant(1.1);
- Cii twoHundred55 = NoiseKernel.constant(255);
- Cii VerticalHeight = NoiseKernel.constant(vtPagerDetails.Height);
- Cii HalfVerticalHeight = NoiseKernel.constant(vtPagerDetails.Height / 2.f);
- Cii falloff = NoiseKernel.constant(2.0 / vtPagerDetails.Height);
- // Create a gradient on the vertical axis to form our ground plane.
- Cii 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.
- // falloff determines the width of the boundary
- Cii VerticalSelect = NoiseKernel.select(Zero, twoHundred55, VerticalGradient, NoiseKernel.constant(0.5), falloff);
- // 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.
- Cii TerrainFractal = NoiseKernel.simplefBm(anl::BasisTypes::BASIS_GRADIENT, anl::InterpolationTypes::INTERP_QUINTIC, vtPagerDetails.Octaves, vtPagerDetails.Frequency, vtPagerDetails.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.
- Cii TerrainScale = NoiseKernel.scaleOffset(TerrainFractal, vtPagerDetails.Scale, vtPagerDetails.Offset);
- // Setting the Z scale of the fractal to 0 will effectively turn the fractal into a heightmap. Larger values allow for the terrain to overlap.
- Cii TerrainZScale = NoiseKernel.scaleZ(TerrainScale, zScale);
- // Finally, apply the Z offset we just calculated from the fractal to our ground plane.
- Cii PerturbGradient = NoiseKernel.translateZ(VerticalSelect, TerrainZScale);
- this->PerturbGradient = new anl::CInstructionIndex(PerturbGradient);
- // Now we want to determine different materials based on a variety of factors.
- // This is made easier by the fact that we're basically generating a heightmap.
- // For now our grass is always going to appear at the top level, so we don't need to do anything fancy.
- Cii GrassZ = NoiseKernel.subtract(HalfVerticalHeight, TerrainZScale);
- this->GrassZ = new anl::CInstructionIndex(GrassZ);
- // To generate pockets of ore we're going to need another noise generator.
- Cii OreFractal = NoiseKernel.simpleRidgedMultifractal(anl::BasisTypes::BASIS_SIMPLEX, anl::InterpolationTypes::INTERP_LINEAR, 2, 5 * vtPagerDetails.Frequency, vtPagerDetails.Seed);
- this->OreFractal = new anl::CInstructionIndex(OreFractal);
- TerrainExecutor = new anl::CNoiseExecutor(this->NoiseKernel);
- }
- ~PrivateData() {
- delete PerturbGradient;
- delete GrassZ;
- delete OreFractal;
- delete TerrainExecutor;
- }
- };
- VoxelData_sp createSphereInVolume(const PolyVox::Region& region)
- {
- const int32_t xSize = region.getUpperX() - region.getLowerX() + 1;
- const int32_t ySize = region.getUpperY() - region.getLowerY() + 1;
- const int32_t zSize = region.getUpperZ() - region.getLowerZ() + 1;
- float fRadius = xSize / 2.2;
- VoxelData_sp voxelData = MakeShareable(new VoxelData(xSize, ySize, zSize));
- //This vector hold the position of the center of the volume
- Vector3DFloat v3dVolCenter(xSize / 2, ySize / 2, zSize / 2);
- //This three-level for loop iterates over every voxel in the volume
- //const float innerBoundary = 0.1f * fRadius;
- for (int z = 0; z < zSize; z++)
- {
- for (int y = 0; y < ySize; y++)
- {
- for (int x = 0; x < xSize; x++)
- {
- //Store our current position as a vector...
- Vector3DFloat v3dCurrentPos(x, y, z);
- //And compute how far the current position is from the center of the volume
- float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();
- uint8_t uVoxelValue = 0;
- float val = fRadius - fDistToCenter; // val is positive when inside sphere
- val = PolyVox::clamp(val, -1.0f, 1.0f); // val is between -1.0 and 1.0
- val += 1.0f; // val is between 0.0 and 2.0
- val *= 127.5f; // val is between 0.0 and 255
- // Cast to int
- uVoxelValue = static_cast<uint8_t>(val);
- MDP88 Voxel;
- Voxel.setDensity(uVoxelValue);
- Voxel.setMaterial(3);
- voxelData->at(x, y, z) = Voxel;
- }
- }
- }
- return voxelData;
- }
- VoxelData_sp buildRegionDetails(FNoiseWorker::PrivateData* m_data, const PolyVox::Region& region) {
- assert(m_data->TerrainExecutor != nullptr);
- const int32_t xSize = region.getUpperX() - region.getLowerX() + 1;
- const int32_t ySize = region.getUpperY() - region.getLowerY() + 1;
- const int32_t zSize = region.getUpperZ() - region.getLowerZ() + 1;
- VoxelData_sp voxelData = MakeShareable(new VoxelData(xSize, ySize, zSize));
- // Now that we have our noise setup, let's loop over our chunk and apply it.
- const auto lowerX = region.getLowerX();
- const auto upperX = region.getUpperX();
- const auto lowerY = region.getLowerY();
- const auto upperY = region.getUpperY();
- const auto lowerZ = region.getLowerZ();
- const auto upperZ = region.getUpperZ();
- for (int x = lowerX; x <= upperX; x++)
- {
- for (int y = lowerY; y <= upperY; y++)
- {
- for (int z = lowerZ; z <= upperZ; z++)
- {
- const int32_t x_index = x - lowerX;
- const int32_t y_index = y - lowerY;
- const int32_t z_index = z - lowerZ;
- // Evaluate the noise
- auto EvaluatedNoise = m_data->TerrainExecutor->evaluateScalar(x, y, z, *m_data->PerturbGradient);
- MDP88 Voxel;
- bool bSolid = EvaluatedNoise >= 127;
- Voxel.setDensity(EvaluatedNoise);
- // Determine what material should be set on the voxel
- // Air = 0
- // Stone = 1
- // Dirt = 2
- // Grass = 3
- // Ore = 4
- int ActualGrassZ = FMath::FloorToInt(m_data->TerrainExecutor->evaluateScalar(x, y, z, *m_data->GrassZ)) - 1;
- int DirtZ = ActualGrassZ - 1;
- int DirtThickness = 3;
- if (bSolid) {
- if (z >= ActualGrassZ)
- {
- Voxel.setMaterial(3);
- }
- else if (z <= DirtZ && z > (DirtZ - DirtThickness))
- {
- Voxel.setMaterial(2);
- }
- else
- {
- auto EvaluatedOreFractal = m_data->TerrainExecutor->evaluateScalar(x, y, z, *m_data->OreFractal);
- if (EvaluatedOreFractal > 1.95)
- Voxel.setMaterial(4);
- else
- Voxel.setMaterial(1);
- }
- }
- else
- {
- Voxel.setMaterial(0);
- }
- voxelData->at(x_index, y_index, z_index) = Voxel;
- }
- }
- }
- return voxelData;
- }
- FNoiseWorker::FNoiseWorker()
- {
- this->inputQueue = MakeShareable(new NoiseThreadRequest_sp_SafeTArray());
- this->completedThreadRequests = MakeShareable(new NoiseThreadRequest_sp_SafeTArray());
- Thread = FRunnableThread::Create(this, TEXT("FNoiseWorker"), 0, TPri_BelowNormal); //windows default = 8mb for thread, could specify more
- }
- void FNoiseWorker::setPagerDetails(VTPagerDetails& pagerDetails) {
- this->m_data = new FNoiseWorker::PrivateData(pagerDetails);
- }
- FNoiseWorker::~FNoiseWorker()
- {
- if (StopTaskCounter.GetValue() == 0) {
- this->Stop();
- }
- onScreen("end thread!");
- delete Thread;
- Thread = NULL;
- delete this->m_data;
- }
- uint32 FNoiseWorker::Run()
- {
- //Initial wait before starting
- while (StopTaskCounter.GetValue() == 0) {
- FPlatformProcess::Sleep(0.1);
- //auto ctr = this->completedThreadRequests->checkout();
- if (this->inputQueue->isEmpty()) {
- continue;
- }
- auto inQ = this->inputQueue->checkout();
- auto ctr = this->completedThreadRequests->checkout();
- NoiseThreadRequest_sp threadReq = *inQ->GetData();
- inQ->RemoveAt(0);
- ctr->Push(threadReq);
- this->inputQueue->checkin();
- this->completedThreadRequests->checkin();
- {
- //onScreen("FNoiseWorker received request for owner# " + FString::FromInt(threadReq->ownerID));
- threadReq->noiseData = buildRegionDetails(this->m_data, threadReq->region);
- //threadReq->noiseData = createSphereInVolume(threadReq->region);
- }
- if ((StopTaskCounter.GetValue() == 0)) {
- threadReq->processedNoiseRequests->push_back(threadReq); // this goes to ATerrainManager::Tick
- }
- }
- this->Exit();
- return 0;
- }
- void FNoiseWorker::Stop() {
- StopTaskCounter.Increment();
- }
- void FNoiseWorker::terminateQueue() {
- this->inputQueue->clear();
- }
Advertisement
Add Comment
Please, Sign In to add comment