void TerrainProceduralDialog::makePertrub(float frequency, float distance) { setWorking(true); PerlinNoise perlin; perlin.setSeed(1); perlin.initGradients(); int u, v; float * temp = new float[m_mapWidth*m_mapDepth]; for (int i = 0; i < m_mapWidth; ++i) for (int j = 0; j < m_mapDepth; ++j) { u = i + (int)(perlin.noise(frequency * i / (float)m_mapWidth, frequency * j / (float)m_mapDepth, 0) * distance); v = j + (int)(perlin.noise(frequency * i / (float)m_mapWidth, frequency * j / (float)m_mapDepth, 1) * distance); if (u < 0) u = 0; if (u >= m_mapWidth) u = m_mapWidth - 1; if (v < 0) v = 0; if (v >= m_mapDepth) v = m_mapDepth - 1; temp[i*m_mapWidth+j] = data[u*m_mapWidth+v]; } for(int i=0;i<m_mapWidth*m_mapDepth;i++) data[i]=temp[i]; delete temp; updateImage(); setWorking(false); }
void generatePerlinNoise(glm::vec3 perlinMatrix[IslandWidth][IslandHeight], double elevation[IslandWidth][IslandHeight]) { PerlinNoise pn; // int x,y; // double n, i, j; // for(x = 0; x < IslandWidth; x++){ // for(y = 0; y < IslandHeight; y++){ // i = (double) x / IslandWidth; // j = (double) y / IslandHeight; // n = 20 * pn.noise((double) i, (double) j, 0.0); // n = n - floor(n); // if(elevation[x][y] == 0){ // elevation[x][y] += ((int) floor(n) % 2) ? n : -n; // } // } // } int i = 0, j = 0, xtemp; double n; int n_int; while(j < IslandHeight) { while(i < IslandWidth) { n = 2.0 * pn.noise((double) i, (double) j, elevation[i][j]); perlinMatrix[i][j].x = 0; perlinMatrix[i][j].y = 0; perlinMatrix[i][j].z = n; i++; } i = 0; j++; } }
T noise(T x, T y, T z) { T sum = 0; T frequency = (T)1; T amplitude = (T)1; T max = (T)0; for (int32_t i = 0; i < (int32_t)octaves; i++) { sum += perlinNoise.noise(x * frequency, y * frequency, z * frequency) * amplitude; max += amplitude; amplitude *= persistence; frequency *= (T)2; } sum = sum / max; return (sum + (T)1.0) / (T)2.0; }
void TerrainProceduralDialog::makePerlinNoise(float seed, float frequency) { setWorking(true); PerlinNoise perlin; perlin.setSeed(seed); perlin.initGradients(); for(int i=0; i<m_mapWidth;i++) for(int j=0; j<m_mapDepth;j++) { float value=perlin.noise(frequency * i / (float)m_mapWidth, frequency * j / (float)m_mapDepth, 0); data[i*m_mapWidth+j]=value; } updateImage(); setWorking(false); }
// Called when the game starts or when spawned void APDemo::BeginPlay() { Super::BeginPlay(); FString GameDir = FPaths::GameDir(); FString CompleteFilePath = GameDir + "map_settings.txt"; FString FileData = ""; FFileHelper::LoadFileToString(FileData, *CompleteFilePath); int map_hash = FCString::Atoi(*FileData); //UE_LOG(LogTemp, Warning, TEXT("map_hash is %i and the path is %s"), map_hash, *CompleteFilePath); pn = PerlinNoise(map_hash); // Create an empty PPM image ppm image(width, height); unsigned int kk = 0; // Visit every pixel of the image and assign a color generated with Perlin noise for (unsigned int i = 0; i < height; ++i) { // y for (unsigned int j = 0; j < width; ++j) { // x double x = (double)j / ((double)width); double y = (double)i / ((double)height); // Typical Perlin noise double n = pn.noise(10 * x, 10 * y, 0.8); // Wood like structure //n = 20 * pn.noise(x, y, 0.8); //n = n - floor(n); n = n < noise_threshold ? 0 : n;//used to create a clear distinction between space and land // Map the values to the [0, 255] interval, for simplicity we use // tones of grey image.r[kk] = floor(255 * n); image.g[kk] = floor(255 * n); image.b[kk] = floor(255 * n); kk++; } } // Save the image in a binary PPM file int result = image.write("figure_8_R.ppm"); }
double * adjustVoronoi(int ** voronoiPositions, double ** voronoiColors, double elevation[IslandWidth][IslandHeight], glm::vec3 landColor[IslandWidth][IslandHeight], int idx){ int x = 0, y = 0, i = 0; double currHeight; double * resVorPos; *voronoiColors = (double *) calloc( idx, sizeof(double) ); resVorPos = (double *) calloc( idx, sizeof(double) ); double maxElev = 0; double elevThresh = 0.4; PerlinNoise pn; double n; int maxrad = 1000, rad ; glm::vec2 center; glm::vec2 loc; center.x = IslandWidth / 2; center.y = IslandHeight / 2; double distanceFromCtr; while(i < idx){ x = (*voronoiPositions)[i]; y = (*voronoiPositions)[i + 1]; loc.x = x; loc.y = y; if( (x >= 0 && x < IslandWidth) && (y >= 0 && y < IslandHeight) ){ distanceFromCtr = (double) glm::length(loc - center); n = pn.noise( (double) x / IslandWidth, (double) y / IslandHeight, 0.0); rad = maxrad * (n - floor(n)); //n = sin(x + y); n *= 1800; resVorPos[i] = normalize(x, IslandWidth); resVorPos[i + 1] = normalize(y, IslandHeight); //z-value currHeight = elevation[x][y]; if(maxElev < currHeight){ maxElev = currHeight ; } // (*voronoiPositions)[i + 2] = -currHeight; // resVorPos[i + 2] = (distanceFromCtr < (IslandRadius + n)) ? -currHeight:0.0f; resVorPos[i + 2] = -currHeight; if(resVorPos[i + 2] > elevThresh){ resVorPos[i + 2] = elevThresh; } // printf("Voronoi pos: (%d, %d) E: %f\n", x, y, resVorPos[i + 2]); // *voronoiColors = (double *) realloc((*voronoiColors), (i+ 3) * sizeof(double) ); // r (*voronoiColors)[i] = landColor[x][y].r; // (*voronoiColors)[i] *= 1.3; // g (*voronoiColors)[i + 1] = landColor[x][y].g; // (*voronoiColors)[i + 1] *= 1.3; // b (*voronoiColors)[i + 2] = landColor[x][y].b; // (*voronoiColors)[i + 2] *= 0.4; // } } else{ if(x < 0){ resVorPos[i] = -1; } if(x >= IslandWidth){ resVorPos[i] = 1; } if(y < 0){ resVorPos[i + 1] = -1; } if(y >= IslandHeight){ resVorPos[i + 1] = 1; } resVorPos[i + 2] = 0; } i += 3; } printf("Max voronoi height: %f", maxElev); return resVorPos; }
// Thoughout the function we delete all in-world coordinates by 200. // This is to make a cube in the real world be equal to a pixel from the map image. void APDemo::Tick( float DeltaTime ) { Super::Tick( DeltaTime ); UWorld* World = GetWorld(); APlayerCameraManager* PlayerCameraManager = World->GetFirstPlayerController()->PlayerCameraManager; FVector cam_position = PlayerCameraManager->GetCameraLocation(); if (br != 0){ //go through brick_to... and remove the marked ones from bricks for (unsigned int i = 0; i < br; ++i){ ABrick* Brick = bricks[bricks_to_be_removed[i]]; bricks.erase(bricks_to_be_removed[i]); Brick->Destroy(); bricks_to_be_removed[i] = ""; } br = 0; } //now go through bricks and mark the new bricks to be removed next frame for (auto it = bricks.begin(); it != bricks.end(); ++it){ FVector brick_loc = it->second->GetActorLocation(); float distance = ( (brick_loc - cam_position).Size() )/200; if (distance >= despawn_dist){ bricks_to_be_removed[br] = it->first; ++br; } } //int spawn_height_sector = (int)floor(cam_position.Z / 200) / 80; //spawn_height = 160 * spawn_height_sector; //this magic tho int spawn_height_sector = (int)floor(cam_position.Z / 200); int sector_offset = spawn_height_sector == 0 ? 0 : (spawn_height_sector / abs(spawn_height_sector)) * 80; spawn_height_sector += sector_offset; spawn_height_sector = spawn_height_sector / 160; spawn_height = 160 * spawn_height_sector; int distance_fwd = 60; int distance_left = 60; int start_i = (int)floor(cam_position.X / 200); int start_j = (int)floor(cam_position.Y / 200); for (int i = start_i - distance_fwd; i < start_i + distance_fwd; ++i) { // y for (int j = start_j - distance_left; j < start_j + distance_left; ++j) { // x double x = (double)(abs(j) % width) / ((double)width);// we use % to make sure we never go out of the defined map double y = (double)(abs(i) % height) / ((double)height); double n = pn.noise(10 * x, 10 * y, 0.8); n = n < noise_threshold ? 0 : n;//used to create a clear distinction between space and land FVector brick_position = FVector(i * 200, j * 200, spawn_height * 200); float distance = ((brick_position - cam_position).Size()) / 200; if (distance < despawn_dist){ string key = to_string(i) + to_string(j); if (n > 0 && !bricks[key]){ float brick_height = n; ABrick* Brick = World->SpawnActor<ABrick>(ABrick::StaticClass()); Brick->SetPositionAndHeight(brick_position, brick_height, noise_threshold); bricks[key] = Brick; } } } } }
// Generate randomized noise and upload it to the 3D texture using staging void updateNoiseTexture() { const uint32_t texMemSize = texture.width * texture.height * texture.depth; uint8_t *data = new uint8_t[texMemSize]; memset(data, 0, texMemSize); // Generate perlin based noise std::cout << "Generating " << texture.width << " x " << texture.height << " x " << texture.depth << " noise texture..." << std::endl; auto tStart = std::chrono::high_resolution_clock::now(); PerlinNoise<float> perlinNoise; FractalNoise<float> fractalNoise(perlinNoise); std::default_random_engine rndEngine(std::random_device{}()); const int32_t noiseType = rand() % 2; const float noiseScale = static_cast<float>(rand() % 10) + 4.0f; #pragma omp parallel for for (int32_t z = 0; z < (int32_t)texture.depth; z++) { for (int32_t y = 0; y < (int32_t)texture.height; y++) { for (int32_t x = 0; x < (int32_t)texture.width; x++) { float nx = (float)x / (float)texture.width; float ny = (float)y / (float)texture.height; float nz = (float)z / (float)texture.depth; #define FRACTAL #ifdef FRACTAL float n = fractalNoise.noise(nx * noiseScale, ny * noiseScale, nz * noiseScale); #else float n = 20.0 * perlinNoise.noise(nx, ny, nz); #endif n = n - floor(n); data[x + y * texture.width + z * texture.width * texture.height] = static_cast<uint8_t>(floor(n * 255)); } } } auto tEnd = std::chrono::high_resolution_clock::now(); auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); std::cout << "Done in " << tDiff << "ms" << std::endl; // Create a host-visible staging buffer that contains the raw image data VkBuffer stagingBuffer; VkDeviceMemory stagingMemory; // Buffer object VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(); bufferCreateInfo.size = texMemSize; bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, &stagingBuffer)); // Allocate host visible memory for data upload VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs = {}; vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs); memAllocInfo.allocationSize = memReqs.size; memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &stagingMemory)); VK_CHECK_RESULT(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0)); // Copy texture data into staging buffer uint8_t *mapped; VK_CHECK_RESULT(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&mapped)); memcpy(mapped, data, texMemSize); vkUnmapMemory(device, stagingMemory); VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); // Image barrier for optimal image // The sub resource range describes the regions of the image we will be transition VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; subresourceRange.layerCount = 1; // Optimal image will be used as destination for the copy, so we must transfer from our // initial undefined image layout to the transfer destination layout vkTools::setImageLayout( copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); // Copy 3D noise data to texture // Setup buffer copy regions VkBufferImageCopy bufferCopyRegion{}; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.mipLevel = 0; bufferCopyRegion.imageSubresource.baseArrayLayer = 0; bufferCopyRegion.imageSubresource.layerCount = 1; bufferCopyRegion.imageExtent.width = texture.width; bufferCopyRegion.imageExtent.height = texture.height; bufferCopyRegion.imageExtent.depth = texture.depth; vkCmdCopyBufferToImage( copyCmd, stagingBuffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); // Change texture image layout to shader read after all mip levels have been copied texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture.imageLayout, subresourceRange); VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); // Clean up staging resources delete[] data; vkFreeMemory(device, stagingMemory, nullptr); vkDestroyBuffer(device, stagingBuffer, nullptr); regenerateNoise = false; }