test version will be rewritten before main.
This commit is contained in:
@@ -29,7 +29,7 @@
|
||||
|
||||
constexpr int Dim = 3;
|
||||
|
||||
template<typename T, typename IndexType = uint16_t>
|
||||
template<typename T, typename IndexType = uint32_t>
|
||||
class Octree {
|
||||
public:
|
||||
using PointType = Eigen::Matrix<float, Dim, 1>;
|
||||
@@ -235,7 +235,7 @@ private:
|
||||
|
||||
float lodFalloffRate_ = 0.1f; // Lower = better, higher = worse. 0-1
|
||||
float lodMinDistance_ = 100.0f;
|
||||
float maxDistance_ = size * size;
|
||||
float maxDistance_ = 100000;
|
||||
|
||||
struct Ray {
|
||||
PointType origin;
|
||||
|
||||
@@ -189,8 +189,7 @@ inline void updateNoiseTexture(NoisePreviewState& state) {
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, state.textureId);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, state.width, state.height,
|
||||
0, GL_RGB, GL_UNSIGNED_BYTE, state.pixelBuffer.data());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, state.width, state.height, 0, GL_RGB, GL_UNSIGNED_BYTE, state.pixelBuffer.data());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
|
||||
@@ -837,6 +837,57 @@ public:
|
||||
|
||||
void addMoon() {
|
||||
///TODO: using planetConfig, add moon(s).
|
||||
TIME_FUNCTION;
|
||||
|
||||
const float realEarthRadiusKm = 6371.0f;
|
||||
const float realMoonRadiusKm = 1737.4f;
|
||||
const float realOrbitKm = 384400.0f;
|
||||
float simScale = config.radius / realEarthRadiusKm;
|
||||
|
||||
float moonRadius = realMoonRadiusKm * simScale;
|
||||
float orbitDistance = realOrbitKm * simScale;
|
||||
|
||||
std::cout << "--- MOON GENERATION ---" << std::endl;
|
||||
std::cout << "Sim Scale: " << simScale << " units/km" << std::endl;
|
||||
std::cout << "Moon Radius: " << moonRadius << " units" << std::endl;
|
||||
std::cout << "Orbit Distance: " << orbitDistance << " units" << std::endl;
|
||||
|
||||
// Place the moon on the Z-axis to keep it distinct from the star (which is on the X-axis)
|
||||
v3 moonCenter = config.center + v3(0.0f, 0.0f, orbitDistance);
|
||||
v3 moonColor = v3(0.7f, 0.7f, 0.72f); // Pale gray color
|
||||
|
||||
// Surface area ratio Moon/Earth is ~0.074. We scale the points to maintain node density.
|
||||
int moonPoints = std::max(1000, static_cast<int>(config.surfacePoints * 0.075f));
|
||||
|
||||
for (int i = 0; i < moonPoints; i++) {
|
||||
float y = 1.0f - (i * 2.0f) / (moonPoints - 1);
|
||||
float radiusY = std::sqrt(1.0f - y * y);
|
||||
float Θ = Φ * i;
|
||||
float x = std::cos(Θ) * radiusY;
|
||||
float z = std::sin(Θ) * radiusY;
|
||||
|
||||
v3 dir(x, y, z);
|
||||
v3 pos = moonCenter + dir * moonRadius;
|
||||
Particle pt;
|
||||
|
||||
pt.altPos = std::make_unique<AltPositions>();
|
||||
pt.altPos->originalPos = pos.cast<Eigen::half>();
|
||||
pt.altPos->noisePos = pos.cast<Eigen::half>();
|
||||
pt.altPos->tectonicPos = pos.cast<Eigen::half>();
|
||||
|
||||
pt.currentPos = pos;
|
||||
pt.originColor = moonColor.cast<Eigen::half>();
|
||||
pt.noiseDisplacement = 0.0f;
|
||||
pt.surface = true;
|
||||
|
||||
config.surfaceNodes.emplace_back(pt);
|
||||
|
||||
grid.set(pt, pt.currentPos, true, pt.originColor.cast<float>(), config.voxelSize, true, 3, 0, 1.0, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
grid.optimize();
|
||||
std::cout << "Moon generation complete. Placed " << moonPoints << " nodes." << std::endl;
|
||||
starAdded = true;
|
||||
}
|
||||
|
||||
void stretchPlanet() {
|
||||
|
||||
232
util/sim/worldbox.hpp
Normal file
232
util/sim/worldbox.hpp
Normal file
@@ -0,0 +1,232 @@
|
||||
#ifndef WORLDBOX_HPP
|
||||
#define WORLDBOX_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
|
||||
#include "../grid/grid3eigen.hpp"
|
||||
#include "../timing_decorator.cpp"
|
||||
|
||||
using v3 = Eigen::Vector3f;
|
||||
|
||||
struct WorldVoxel {
|
||||
float nutrients = 1.0f;
|
||||
float moisture = 0.5f;
|
||||
int type = 0;
|
||||
|
||||
WorldVoxel() = default;
|
||||
|
||||
WorldVoxel(float nut, float mois, int t) : nutrients(nut), moisture(mois), type(t) {}
|
||||
};
|
||||
|
||||
struct WorldBoxConfig {
|
||||
v3 center = v3(0, 0, 0);
|
||||
float worldSizeX = 1000.0f;
|
||||
float worldSizeZ = 1000.0f;
|
||||
float worldDepth = 20.0f;
|
||||
|
||||
float voxelSize = 2.0f;
|
||||
v3 baseDirtColor = v3(0.36f, 0.25f, 0.14f);
|
||||
v3 baseRockColor = v3(0.45f, 0.45f, 0.45f);
|
||||
|
||||
float gridSizeCubeMin = 1024.0f;
|
||||
|
||||
// Grass Config
|
||||
float grassDensity = 0.05f;
|
||||
v3 grassColorBase = v3(0.2f, 0.6f, 0.15f);
|
||||
|
||||
// Star Config
|
||||
bool enableStarRotation = false; // Off by default
|
||||
float starOrbitRadius = 800.0f;
|
||||
float starPanelSize = 100.0f;
|
||||
float starVoxelSize = 10.0f;
|
||||
v3 starColor = v3(1.0f, 0.95f, 0.8f);
|
||||
float starSpeed = 0.2f; // Radians per second
|
||||
float starAngle = 0.0f;
|
||||
};
|
||||
|
||||
class worldboxsim {
|
||||
public:
|
||||
WorldBoxConfig config;
|
||||
Octree<WorldVoxel> grid;
|
||||
std::mt19937 rng;
|
||||
std::vector<v3> starVoxelPositions;
|
||||
|
||||
worldboxsim() : rng(42) {
|
||||
config = WorldBoxConfig();
|
||||
grid = Octree<WorldVoxel>(v3(-config.gridSizeCubeMin, -config.gridSizeCubeMin, -config.gridSizeCubeMin),v3(config.gridSizeCubeMin, config.gridSizeCubeMin, config.gridSizeCubeMin), 16, 32);
|
||||
grid.setBackgroundColor(v3(0.53f, 0.81f, 0.92f));
|
||||
}
|
||||
|
||||
void updateStar(float dt) {
|
||||
// If turned off, despawn current star if it exists
|
||||
if (!config.enableStarRotation) {
|
||||
if (!starVoxelPositions.empty()) {
|
||||
WorldVoxel emptyVoxel;
|
||||
for(const auto& pos : starVoxelPositions) {
|
||||
grid.set(emptyVoxel, pos, false, v3(0,0,0), config.starVoxelSize, false, 0, 0);
|
||||
}
|
||||
starVoxelPositions.clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate rotation
|
||||
config.starAngle += dt * config.starSpeed;
|
||||
if (config.starAngle > 2 * M_PI) config.starAngle -= 2 * M_PI;
|
||||
|
||||
// 1. Erase the old star voxels
|
||||
WorldVoxel emptyVoxel;
|
||||
for(const auto& pos : starVoxelPositions) {
|
||||
grid.set(emptyVoxel, pos, false, v3(0,0,0), config.starVoxelSize, false, 0, 0);
|
||||
}
|
||||
starVoxelPositions.clear();
|
||||
|
||||
// 2. Calculate new center of star (orbiting on the X/Y plane)
|
||||
v3 starCenter(cos(config.starAngle) * config.starOrbitRadius, sin(config.starAngle) * config.starOrbitRadius, 0.0f);
|
||||
|
||||
// 3. Create a flat panel facing the origin
|
||||
v3 n = -starCenter.normalized();
|
||||
v3 worldUp(0, 1, 0);
|
||||
if (std::abs(n.dot(worldUp)) > 0.99f) worldUp = v3(0, 0, 1);
|
||||
v3 right = worldUp.cross(n).normalized();
|
||||
v3 up = n.cross(right).normalized();
|
||||
|
||||
int halfGrid = std::max(1, static_cast<int>((config.starPanelSize / config.starVoxelSize) / 2.0f));
|
||||
WorldVoxel starVoxel(0.0f, 0.0f, 3); // Type 3 = Star
|
||||
|
||||
for (int i = -halfGrid; i <= halfGrid; ++i) {
|
||||
for (int j = -halfGrid; j <= halfGrid; ++j) {
|
||||
v3 pos = starCenter + (right * (i * config.starVoxelSize)) + (up * (j * config.starVoxelSize));
|
||||
// Add star voxel with high material/emission flag
|
||||
grid.set(starVoxel, pos, true, config.starColor, config.starVoxelSize, true, 1, 1);
|
||||
starVoxelPositions.push_back(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generateGrass() {
|
||||
TIME_FUNCTION;
|
||||
float halfX = config.worldSizeX / 2.0f;
|
||||
float halfZ = config.worldSizeZ / 2.0f;
|
||||
float surfaceY = 0.0f;
|
||||
|
||||
int stepsX = static_cast<int>(std::round(config.worldSizeX / config.voxelSize)) + 1;
|
||||
int stepsZ = static_cast<int>(std::round(config.worldSizeZ / config.voxelSize)) + 1;
|
||||
|
||||
int grassCount = 0;
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 local_rng(rd() ^ std::hash<std::thread::id>()(std::this_thread::get_id()));
|
||||
std::uniform_real_distribution<float> probDist(0.0f, 1.0f);
|
||||
std::uniform_int_distribution<int> grassHeightDist(1, 8);
|
||||
|
||||
#pragma omp for schedule(static) collapse(2)
|
||||
for (int i = 0; i < stepsX; ++i) {
|
||||
for (int j = 0; j < stepsZ; ++j) {
|
||||
|
||||
float x = -halfX + i * config.voxelSize;
|
||||
float z = -halfZ + j * config.voxelSize;
|
||||
|
||||
if (x > halfX || z > halfZ) continue;
|
||||
|
||||
if (probDist(local_rng) < config.grassDensity) {
|
||||
int gHeight = grassHeightDist(local_rng);
|
||||
float gSize = config.voxelSize / 25.0f;
|
||||
|
||||
std::uniform_real_distribution<float> offDist(-config.voxelSize/2.0f + gSize/2.0f, config.voxelSize/2.0f - gSize/2.0f);
|
||||
float offsetX = offDist(local_rng);
|
||||
float offsetZ = offDist(local_rng);
|
||||
|
||||
WorldVoxel gVox(1.0f, 0.8f, 2); // Type 2 = Grass
|
||||
float baseY = surfaceY + (config.voxelSize / 2.0f) + (gSize / 2.0f);
|
||||
|
||||
#pragma omp critical
|
||||
{
|
||||
for (int g = 0; g < gHeight; ++g) {
|
||||
v3 gPos(x + offsetX, baseY + g * gSize, z + offsetZ);
|
||||
grid.set(gVox, gPos, true, config.grassColorBase, gSize, true, 1, 0);
|
||||
grassCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "Grass generation complete. Placed " << grassCount << " grass voxels." << std::endl;
|
||||
}
|
||||
|
||||
void generateFlatWorld() {
|
||||
TIME_FUNCTION;
|
||||
grid.clear();
|
||||
|
||||
float halfX = config.worldSizeX / 2.0f;
|
||||
float halfZ = config.worldSizeZ / 2.0f;
|
||||
float surfaceY = 0.0f;
|
||||
|
||||
// 1. Calculate integer bounds to satisfy OpenMP
|
||||
int stepsX = static_cast<int>(std::round(config.worldSizeX / config.voxelSize)) + 1;
|
||||
int stepsZ = static_cast<int>(std::round(config.worldSizeZ / config.voxelSize)) + 1;
|
||||
int stepsY = static_cast<int>(std::round(config.worldDepth / config.voxelSize)) + 1;
|
||||
size_t maxSteps = stepsX * stepsZ * stepsY;
|
||||
|
||||
int nodeCount = 0;
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 local_rng(rd());
|
||||
std::uniform_real_distribution<float> colorVar(-0.03f, 0.03f);
|
||||
std::uniform_real_distribution<float> nutrientVar(0.8f, 1.2f);
|
||||
|
||||
#pragma omp parallel for schedule(static) collapse(3)
|
||||
for (int i = 0; i < stepsX; ++i) {
|
||||
for (int j = 0; j < stepsZ; ++j) {
|
||||
for (int k = 0; k < stepsY; ++k) {
|
||||
|
||||
float x = -halfX + i * config.voxelSize;
|
||||
float z = -halfZ + j * config.voxelSize;
|
||||
float y = surfaceY - k * config.voxelSize;
|
||||
|
||||
if (x > halfX || z > halfZ || y < surfaceY - config.worldDepth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WorldVoxel voxel;
|
||||
v3 color;
|
||||
|
||||
float depthRatio = std::abs(y - surfaceY) / config.worldDepth;
|
||||
|
||||
if (depthRatio > 0.8f) {
|
||||
voxel.type = 1;
|
||||
voxel.nutrients = 0.1f;
|
||||
color = config.baseRockColor;
|
||||
} else {
|
||||
voxel.type = 0;
|
||||
voxel.nutrients = 1.0f - depthRatio;
|
||||
color = config.baseDirtColor;
|
||||
}
|
||||
|
||||
v3 pos(x, y, z);
|
||||
|
||||
#pragma omp critical
|
||||
grid.set(voxel, pos, true, color, config.voxelSize, true, 1, 0);
|
||||
// nodeCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "World generation complete. Placed " << nodeCount << " voxels." << std::endl;
|
||||
}
|
||||
|
||||
void clearWorld() {
|
||||
grid.clear();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user