119 lines
5.1 KiB
C++
119 lines
5.1 KiB
C++
#pragma once
|
|
|
|
#include "core/world/generator/Cave.hpp"
|
|
#include "core/geometry/math.hpp"
|
|
#include "./Core.hpp"
|
|
|
|
namespace world::generator {
|
|
|
|
enum class PlanetShape { Cube, Sphere };
|
|
|
|
/// Abstract shaped planet generator
|
|
template <PlanetShape PS>
|
|
class Planet final: public Abstract {
|
|
private:
|
|
template<uint32_t level>
|
|
inline void generate(const voxel_pos& min, voxels& out) const {
|
|
constexpr uint32_t LENGTH = 1u << level;
|
|
constexpr size_t SIZE = glm::pow3(LENGTH);
|
|
constexpr auto VEC = glm::i32vec3(LENGTH);
|
|
const auto densitySet = density.getRaw(min, VEC);
|
|
const auto displacementSet = displacement.getRaw(min, VEC);
|
|
const auto& IDS = world::module::core::Core::Get()->ids;
|
|
const auto genAt = [&](size_t i) -> Voxel {
|
|
const auto heightRatio = ((float)getHeight(min + voxel_pos(glm::fromIdx(i))) - params.height) / params.height;
|
|
|
|
const auto verticalDensityOffset = heightRatio / (heightRatio >= 0 ? params.surface_roughness : params.depth_roughness);
|
|
const auto density = std::min((densitySet.get()[i] + params.density - verticalDensityOffset) * params.granularity, 1.f) * Voxel::DENSITY_MAX;
|
|
|
|
if (density > 0) {
|
|
const auto material = [&]() -> int {
|
|
const auto noisedHeightRatio = heightRatio - displacementSet.get()[i] * params.beach_displacement;
|
|
if(noisedHeightRatio >= 0) {
|
|
return densitySet.get()[i] + params.density < ((heightRatio + 0.007f) / params.surface_roughness) ? IDS.GRASS : IDS.DIRT;
|
|
} else {
|
|
return noisedHeightRatio >= -params.beach_depth ? IDS.SAND : IDS.ROCK;
|
|
}
|
|
}();
|
|
return Voxel(material, density);
|
|
} else {
|
|
if (heightRatio >= 0) {
|
|
return Voxel(IDS.AIR, (heightRatio < params.surface_roughness) * Voxel::DENSITY_MAX);
|
|
} else {
|
|
return Voxel(IDS.WATER, std::clamp<double>(-heightRatio * params.height, 0.f, 1.f) * Voxel::DENSITY_MAX);
|
|
}
|
|
}
|
|
};
|
|
|
|
const auto sample = genAt(0);
|
|
bool unique = true;
|
|
out.resize(SIZE);
|
|
for (size_t i = 0; i < SIZE; i++) {
|
|
out[i] = genAt(i);
|
|
if (unique && out[i].value != sample.value)
|
|
unique = false;
|
|
}
|
|
if (unique) {
|
|
out = voxels{sample};
|
|
}
|
|
}
|
|
|
|
public:
|
|
struct Params: Cave::Params {
|
|
Params(voxel_pos::value_type height, int seed = 42, float surface_roughness = .1, float depth_roughness = .05, float density = 0, float gran = 30):
|
|
Cave::Params(seed, density, gran), height(height), surface_roughness(surface_roughness), depth_roughness(depth_roughness) { }
|
|
|
|
/// Sea level (minimal density)
|
|
voxel_pos::value_type height;
|
|
/// Density decrease over height
|
|
float surface_roughness;
|
|
/// Density decrease under height
|
|
float depth_roughness;
|
|
/// Sea border depth
|
|
float beach_depth = .01f;
|
|
/// Sea ground displacement
|
|
float beach_displacement = .01f;
|
|
};
|
|
Planet(const Params& p) : params(p), density(Noise::SimplexFractal(p.seed)), displacement(Noise::Simplex(p.seed * 5, .01)) {}
|
|
|
|
void generate5(const voxel_pos &min, voxels &out) override {
|
|
generate<5>(min, out);
|
|
}
|
|
glm::vec3 getGravity(const voxel_pos& pos) const override {
|
|
const auto heightRatio = static_cast<float>((getHeight(pos) - params.height) / params.height);
|
|
const auto scale = params.height >> 7;
|
|
const auto mass = scale * scale * scale; //FIXME: average material density
|
|
return -getSurfaceDir(pos) * std::max<float>(0, 1.f - heightRatio * heightRatio) * glm::vec3(mass);
|
|
}
|
|
std::optional<double> getCurvature() const override {
|
|
if constexpr (shape == PlanetShape::Cube) {
|
|
return params.height * (1.1 + params.surface_roughness);
|
|
}
|
|
return {};
|
|
}
|
|
private:
|
|
static constexpr PlanetShape shape = PS;
|
|
static constexpr glm::f64 getHeight(const voxel_pos &p) {
|
|
if constexpr(shape == PlanetShape::Cube) {
|
|
return glm::max_axis(glm::abs(p));
|
|
} else {
|
|
return glm::length(glm::dvec3(p));
|
|
}
|
|
}
|
|
/// Centre inverse direction
|
|
// NOTE: So center point is consider mass center
|
|
static constexpr glm::vec3 getSurfaceDir(const voxel_pos &p) {
|
|
if constexpr(shape == PlanetShape::Cube) {
|
|
return glm::inormalize(p);
|
|
} else {
|
|
return glm::normalize(glm::dvec3(p));
|
|
}
|
|
}
|
|
Params params;
|
|
Noise density;
|
|
Noise displacement;
|
|
};
|
|
using CubicPlanet = Planet<PlanetShape::Cube>;
|
|
using RoundPlanet = Planet<PlanetShape::Sphere>;
|
|
|
|
} |