meh2
This commit is contained in:
322
latlonv.cpp
Normal file
322
latlonv.cpp
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_impl_glfw.h>
|
||||||
|
#include <imgui_impl_opengl3.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
#include <random>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
struct Voxel {
|
||||||
|
float density;
|
||||||
|
unsigned char material; // 0: air, 1: rock, 2: dirt, 3: grass
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlanetConfig {
|
||||||
|
int resolution = 64;
|
||||||
|
float radius = 10.0f;
|
||||||
|
float noiseScale = 0.1f;
|
||||||
|
float amplitude = 1.0f;
|
||||||
|
int seed = 42;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SphericalVoxelPlanet {
|
||||||
|
private:
|
||||||
|
std::vector<Voxel> voxels;
|
||||||
|
PlanetConfig config;
|
||||||
|
std::vector<float> distanceField;
|
||||||
|
GLuint textureID;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SphericalVoxelPlanet() : textureID(0) {
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
~SphericalVoxelPlanet() {
|
||||||
|
if (textureID) {
|
||||||
|
glDeleteTextures(1, &textureID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert spherical to Cartesian coordinates
|
||||||
|
static glm::vec3 sphericalToCartesian(float lat, float lon, float dist) {
|
||||||
|
float latRad = glm::radians(lat);
|
||||||
|
float lonRad = glm::radians(lon);
|
||||||
|
return glm::vec3(
|
||||||
|
dist * cos(latRad) * cos(lonRad),
|
||||||
|
dist * cos(latRad) * sin(lonRad),
|
||||||
|
dist * sin(latRad)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3D noise function for spherical coordinates
|
||||||
|
float sphericalNoise(float lat, float lon, float r, int seed) {
|
||||||
|
glm::vec3 pos = sphericalToCartesian(lat, lon, 1.0f);
|
||||||
|
pos *= config.noiseScale;
|
||||||
|
pos.x += seed;
|
||||||
|
|
||||||
|
// Simple noise function
|
||||||
|
float fx = pos.x * 12.9898f + pos.y * 78.233f + pos.z * 137.631f;
|
||||||
|
return glm::fract(sin(fx) * 43758.5453f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate() {
|
||||||
|
int res = config.resolution;
|
||||||
|
voxels.resize(res * res * res);
|
||||||
|
distanceField.resize(res * res * res);
|
||||||
|
|
||||||
|
float latStep = 180.0f / res;
|
||||||
|
float lonStep = 360.0f / res;
|
||||||
|
float distStep = config.radius * 2.0f / res;
|
||||||
|
|
||||||
|
for (int i = 0; i < res; i++) { // latitude
|
||||||
|
float lat = -90.0f + i * latStep;
|
||||||
|
float latRad = glm::radians(lat);
|
||||||
|
|
||||||
|
for (int j = 0; j < res; j++) { // longitude
|
||||||
|
float lon = j * lonStep;
|
||||||
|
|
||||||
|
for (int k = 0; k < res; k++) { // distance from center
|
||||||
|
float dist = k * distStep;
|
||||||
|
float normalizedDist = dist / (config.radius * 2.0f);
|
||||||
|
|
||||||
|
int idx = i * res * res + j * res + k;
|
||||||
|
|
||||||
|
// Base density (sphere)
|
||||||
|
float baseDensity = config.radius - dist;
|
||||||
|
|
||||||
|
// Add noise based on latitude and longitude
|
||||||
|
float noise = sphericalNoise(lat, lon, dist, config.seed);
|
||||||
|
float altitude = 1.0f - std::abs(lat / 90.0f); // Poles are higher
|
||||||
|
|
||||||
|
float finalDensity = baseDensity + noise * config.amplitude * altitude;
|
||||||
|
|
||||||
|
distanceField[idx] = finalDensity;
|
||||||
|
|
||||||
|
// Assign material based on density and position
|
||||||
|
if (finalDensity > 0.5f) {
|
||||||
|
if (k > res * 0.9f) { // Surface
|
||||||
|
voxels[idx].material = 3; // Grass
|
||||||
|
} else if (k > res * 0.7f) {
|
||||||
|
voxels[idx].material = 2; // Dirt
|
||||||
|
} else {
|
||||||
|
voxels[idx].material = 1; // Rock
|
||||||
|
}
|
||||||
|
voxels[idx].density = 1.0f;
|
||||||
|
} else {
|
||||||
|
voxels[idx].material = 0; // Air
|
||||||
|
voxels[idx].density = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateTexture() {
|
||||||
|
int res = config.resolution;
|
||||||
|
std::vector<unsigned char> textureData(res * res * res * 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < res; i++) {
|
||||||
|
for (int j = 0; j < res; j++) {
|
||||||
|
for (int k = 0; k < res; k++) {
|
||||||
|
int idx = i * res * res + j * res + k;
|
||||||
|
int texIdx = (i * res * res + j * res + k) * 3;
|
||||||
|
|
||||||
|
switch (voxels[idx].material) {
|
||||||
|
case 0: // Air
|
||||||
|
textureData[texIdx] = 0;
|
||||||
|
textureData[texIdx + 1] = 0;
|
||||||
|
textureData[texIdx + 2] = 0;
|
||||||
|
break;
|
||||||
|
case 1: // Rock
|
||||||
|
textureData[texIdx] = 100;
|
||||||
|
textureData[texIdx + 1] = 100;
|
||||||
|
textureData[texIdx + 2] = 100;
|
||||||
|
break;
|
||||||
|
case 2: // Dirt
|
||||||
|
textureData[texIdx] = 101;
|
||||||
|
textureData[texIdx + 1] = 67;
|
||||||
|
textureData[texIdx + 2] = 33;
|
||||||
|
break;
|
||||||
|
case 3: // Grass
|
||||||
|
textureData[texIdx] = 34;
|
||||||
|
textureData[texIdx + 1] = 139;
|
||||||
|
textureData[texIdx + 2] = 34;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureID == 0) {
|
||||||
|
glGenTextures(1, &textureID);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_3D, textureID);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, res, res, res, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderUI() {
|
||||||
|
ImGui::Begin("Planet Generator");
|
||||||
|
|
||||||
|
if (ImGui::SliderInt("Resolution", &config.resolution, 32, 128)) {
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::SliderFloat("Radius", &config.radius, 5.0f, 20.0f)) {
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::SliderFloat("Noise Scale", &config.noiseScale, 0.01f, 0.5f)) {
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::SliderFloat("Amplitude", &config.amplitude, 0.0f, 3.0f)) {
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::SliderInt("Seed", &config.seed, 0, 1000)) {
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("Randomize Seed")) {
|
||||||
|
config.seed = rand() % 1000;
|
||||||
|
generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderPlanet() {
|
||||||
|
// Simple raycasting visualization using distance field
|
||||||
|
// This is a basic implementation - for better results, implement proper raycasting
|
||||||
|
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
|
||||||
|
ImVec2 center = ImGui::GetIO().DisplaySize * 0.5f;
|
||||||
|
float displaySize = std::min(ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y) * 0.4f;
|
||||||
|
|
||||||
|
int slices = 32;
|
||||||
|
float angleStep = 2.0f * 3.14159f / slices;
|
||||||
|
|
||||||
|
// Draw planet outline
|
||||||
|
for (int i = 0; i < slices; i++) {
|
||||||
|
float angle1 = i * angleStep;
|
||||||
|
float angle2 = (i + 1) % slices * angleStep;
|
||||||
|
|
||||||
|
ImVec2 p1 = center + ImVec2(cos(angle1) * displaySize, sin(angle1) * displaySize);
|
||||||
|
ImVec2 p2 = center + ImVec2(cos(angle2) * displaySize, sin(angle2) * displaySize);
|
||||||
|
|
||||||
|
drawList->AddLine(p1, p2, IM_COL32(255, 255, 255, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw some sample voxels
|
||||||
|
int res = config.resolution;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
for (int j = 0; j < 8; j++) {
|
||||||
|
float lat = -90.0f + 180.0f * (i / 7.0f);
|
||||||
|
float lon = 360.0f * (j / 7.0f);
|
||||||
|
|
||||||
|
// Find surface voxel
|
||||||
|
for (int k = res - 1; k >= 0; k--) {
|
||||||
|
int idx = (i * res / 8) * res * res + (j * res / 8) * res + k;
|
||||||
|
if (voxels[idx].material != 0) {
|
||||||
|
// Convert spherical to screen coordinates
|
||||||
|
float latRad = glm::radians(lat);
|
||||||
|
float lonRad = glm::radians(lon);
|
||||||
|
float dist = (k / (float)res) * config.radius * 2.0f;
|
||||||
|
|
||||||
|
float screenDist = (dist / (config.radius * 2.0f)) * displaySize;
|
||||||
|
ImVec2 pos = center + ImVec2(
|
||||||
|
cos(latRad) * cos(lonRad) * screenDist,
|
||||||
|
sin(latRad) * screenDist
|
||||||
|
);
|
||||||
|
|
||||||
|
// Color based on material
|
||||||
|
ImU32 color;
|
||||||
|
switch (voxels[idx].material) {
|
||||||
|
case 1: color = IM_COL32(100, 100, 100, 255); break;
|
||||||
|
case 2: color = IM_COL32(101, 67, 33, 255); break;
|
||||||
|
case 3: color = IM_COL32(34, 139, 34, 255); break;
|
||||||
|
default: color = IM_COL32(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color != 0) {
|
||||||
|
drawList->AddCircleFilled(pos, 2.0f, color);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// GLFW initialization
|
||||||
|
if (!glfwInit()) return -1;
|
||||||
|
|
||||||
|
GLFWwindow* window = glfwCreateWindow(1280, 720, "Voxel Planet Generator", NULL, NULL);
|
||||||
|
if (!window) {
|
||||||
|
glfwTerminate();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
glfwSwapInterval(1);
|
||||||
|
|
||||||
|
// ImGui initialization
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 130");
|
||||||
|
|
||||||
|
SphericalVoxelPlanet planet;
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
while (!glfwWindowShouldClose(window)) {
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
// Start ImGui frame
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
// Render UI
|
||||||
|
planet.renderUI();
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
int display_w, display_h;
|
||||||
|
glfwGetFramebufferSize(window, &display_w, &display_h);
|
||||||
|
glViewport(0, 0, display_w, display_h);
|
||||||
|
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// Render planet
|
||||||
|
planet.renderPlanet();
|
||||||
|
|
||||||
|
// Render ImGui
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
ImGui_ImplGlfw_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
|
glfwDestroyWindow(window);
|
||||||
|
glfwTerminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
285
tests/g3test.cpp
Normal file
285
tests/g3test.cpp
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
#include "../util/grid/grid3.hpp"
|
||||||
|
#include "../util/output/bmpwriter.hpp"
|
||||||
|
#include "../util/noise/pnoise2.hpp"
|
||||||
|
#include "../util/timing_decorator.cpp"
|
||||||
|
#include <cmath>
|
||||||
|
#include <random>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
// Separate component storage
|
||||||
|
class ComponentManager {
|
||||||
|
private:
|
||||||
|
std::unordered_map<size_t, Vec4ui8> colors_;
|
||||||
|
std::unordered_map<size_t, float> sizes_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_color(size_t id, const Vec4ui8& color) { colors_[id] = color; }
|
||||||
|
Vec4ui8 get_color(size_t id) const {
|
||||||
|
auto it = colors_.find(id);
|
||||||
|
return it != colors_.end() ? it->second : Vec4ui8(1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate noise-based positions
|
||||||
|
std::vector<Vec3f> generate_noise_positions(int width, int height, float scale = 0.01f, float threshold = 0.3f) {
|
||||||
|
std::vector<Vec3f> positions;
|
||||||
|
PNoise2 noise_generator(std::random_device{}());
|
||||||
|
|
||||||
|
// Generate positions based on 2D noise
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
// Convert to normalized coordinates
|
||||||
|
float nx = static_cast<float>(x) / width;
|
||||||
|
float ny = static_cast<float>(y) / height;
|
||||||
|
|
||||||
|
// Generate noise at multiple octaves for more interesting patterns
|
||||||
|
float noise_value = 0.0f;
|
||||||
|
float amplitude = 1.0f;
|
||||||
|
float frequency = 1.0f;
|
||||||
|
float max_value = 0.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
Vec2 sample_point(nx * frequency * scale, ny * frequency * scale);
|
||||||
|
noise_value += amplitude * noise_generator.permute(sample_point);
|
||||||
|
max_value += amplitude;
|
||||||
|
amplitude *= 0.5f;
|
||||||
|
frequency *= 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
noise_value = (noise_value / max_value + 1.0f) * 0.5f; // Normalize to [0, 1]
|
||||||
|
|
||||||
|
// Threshold to create sparse distribution
|
||||||
|
if (noise_value > threshold) {
|
||||||
|
// Map to world coordinates [-512, 512]
|
||||||
|
float world_x = (nx * 2.0f - 1.0f) * 512.0f;
|
||||||
|
float world_y = (ny * 2.0f - 1.0f) * 512.0f;
|
||||||
|
float world_z = noise_value * 100.0f; // Use noise value for height
|
||||||
|
|
||||||
|
positions.emplace_back(world_x, world_y, world_z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate 3D noise-based positions (more varied in 3D space)
|
||||||
|
std::vector<Vec3f> generate_3d_noise_positions(int grid_size, float scale = 0.02f, float threshold = 0.4f) {
|
||||||
|
std::vector<Vec3f> positions;
|
||||||
|
PNoise2 noise_generator(std::random_device{}());
|
||||||
|
int sizehalf = grid_size / 2;
|
||||||
|
for (int x = 0; x < grid_size; x++) {
|
||||||
|
for (int y = 0; y < grid_size; y++) {
|
||||||
|
for (int z = 0; z < grid_size; z++) {
|
||||||
|
// Convert to normalized coordinates
|
||||||
|
float nx = static_cast<float>(x) / sizehalf;
|
||||||
|
float ny = static_cast<float>(y) / sizehalf;
|
||||||
|
float nz = static_cast<float>(z) / sizehalf;
|
||||||
|
|
||||||
|
// Generate 3D noise
|
||||||
|
Vec3f sample_point(nx, ny, nz);
|
||||||
|
float noise_value = noise_generator.permute(sample_point);
|
||||||
|
|
||||||
|
// Threshold to create sparse distribution
|
||||||
|
if (noise_value > threshold) {
|
||||||
|
// Map to world coordinates [-512, 512]
|
||||||
|
float world_x = (x - sizehalf);
|
||||||
|
float world_y = (y - sizehalf);
|
||||||
|
float world_z = (z - sizehalf);
|
||||||
|
|
||||||
|
positions.emplace_back(world_x, world_y, world_z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate gradient color based on position
|
||||||
|
Vec4ui8 get_gradient_color(const Vec3f& pos, const Vec3f& min_pos, const Vec3f& max_pos) {
|
||||||
|
// Normalize position to [0, 1]
|
||||||
|
Vec3f normalized(
|
||||||
|
(pos.x - min_pos.x) / (max_pos.x - min_pos.x),
|
||||||
|
(pos.y - min_pos.y) / (max_pos.y - min_pos.y),
|
||||||
|
(pos.z - min_pos.z) / (max_pos.z - min_pos.z)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create RGB gradient based on normalized coordinates
|
||||||
|
uint8_t r = static_cast<uint8_t>(normalized.x * 255);
|
||||||
|
uint8_t g = static_cast<uint8_t>(normalized.y * 255);
|
||||||
|
uint8_t b = static_cast<uint8_t>(normalized.z * 255);
|
||||||
|
|
||||||
|
return Vec4ui8(r, g, b, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate noise-based color
|
||||||
|
Vec4ui8 get_noise_color(const Vec3f& pos, PNoise2& noise_generator) {
|
||||||
|
// Use noise to generate color
|
||||||
|
Vec3f sample_point(pos.x * 0.005f, pos.y * 0.005f, pos.z * 0.005f);
|
||||||
|
float noise_r = noise_generator.permute(sample_point);
|
||||||
|
noise_r = (noise_r + 1.0f) * 0.5f; // Normalize to [0, 1]
|
||||||
|
|
||||||
|
sample_point = Vec3f(pos.x * 0.007f, pos.y * 0.007f, pos.z * 0.007f);
|
||||||
|
float noise_g = noise_generator.permute(sample_point);
|
||||||
|
noise_g = (noise_g + 1.0f) * 0.5f;
|
||||||
|
|
||||||
|
sample_point = Vec3f(pos.x * 0.009f, pos.y * 0.009f, pos.z * 0.009f);
|
||||||
|
float noise_b = noise_generator.permute(sample_point);
|
||||||
|
noise_b = (noise_b + 1.0f) * 0.5f;
|
||||||
|
|
||||||
|
uint8_t r = static_cast<uint8_t>(noise_r * 255);
|
||||||
|
uint8_t g = static_cast<uint8_t>(noise_g * 255);
|
||||||
|
uint8_t b = static_cast<uint8_t>(noise_b * 255);
|
||||||
|
|
||||||
|
return Vec4ui8(r, g, b, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to save frame with given filename
|
||||||
|
bool save_frame(const frame& f, const std::string& filename) {
|
||||||
|
return BMPWriter::saveBMP(filename, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create directory if it doesn't exist
|
||||||
|
void ensure_directory(const std::string& path) {
|
||||||
|
std::filesystem::create_directories(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Create output directory
|
||||||
|
ensure_directory("output");
|
||||||
|
|
||||||
|
// Create pure spatial grid
|
||||||
|
Grid3 grid(10.0f, 15.0f); // Larger cell size for sparse distribution
|
||||||
|
|
||||||
|
// Separate component storage
|
||||||
|
ComponentManager components;
|
||||||
|
|
||||||
|
// Generate noise-based positions
|
||||||
|
std::cout << "Generating noise-based positions..." << std::endl;
|
||||||
|
|
||||||
|
// Option 1: 2D noise (faster)
|
||||||
|
// auto positions = generate_noise_positions(200, 200, 0.02f, 0.4f);
|
||||||
|
|
||||||
|
// Option 2: 3D noise (more interesting, but slower)
|
||||||
|
auto positions = generate_3d_noise_positions(1024, 0.05f, 0.5f);
|
||||||
|
|
||||||
|
std::cout << "Generated " << positions.size() << " positions" << std::endl;
|
||||||
|
|
||||||
|
// Add positions to grid
|
||||||
|
std::cout << "Adding positions to grid..." << std::endl;
|
||||||
|
std::vector<size_t> ids = grid.bulk_add_positions(positions);
|
||||||
|
|
||||||
|
// Generate bounds for color gradient
|
||||||
|
auto bounds = grid.get_bounds();
|
||||||
|
Vec3f min_pos = bounds.first;
|
||||||
|
Vec3f max_pos = bounds.second;
|
||||||
|
|
||||||
|
// Create noise generator for colors
|
||||||
|
PNoise2 color_noise_generator(42); // Fixed seed for consistent colors
|
||||||
|
|
||||||
|
// Assign colors to components
|
||||||
|
std::cout << "Assigning colors..." << std::endl;
|
||||||
|
for (size_t i = 0; i < ids.size(); i++) {
|
||||||
|
Vec3f pos = grid.get_position(ids[i]);
|
||||||
|
|
||||||
|
// Choose color method:
|
||||||
|
// Vec4ui8 color = get_gradient_color(pos, min_pos, max_pos);
|
||||||
|
Vec4ui8 color = get_noise_color(pos, color_noise_generator);
|
||||||
|
|
||||||
|
components.set_color(ids[i], color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query neighbors for first few points (optional)
|
||||||
|
if (!ids.empty()) {
|
||||||
|
auto neighbors = grid.get_neighbors(ids[0]);
|
||||||
|
std::cout << "First point has " << neighbors.size() << " neighbors" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Region to render (full noise map area)
|
||||||
|
Vec3f render_min(-512, -512, -512);
|
||||||
|
Vec3f render_max(512, 512, 512);
|
||||||
|
Vec2 resolution(1024, 1024); // Higher resolution for better detail
|
||||||
|
|
||||||
|
// Define multiple view angles
|
||||||
|
struct ViewAngle {
|
||||||
|
std::string name;
|
||||||
|
Vec3f eye_position;
|
||||||
|
Vec3f look_at;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ViewAngle> view_angles = {
|
||||||
|
// Orthographic views
|
||||||
|
{"front", Vec3f(0, 0, -800), Vec3f(0, 0, 0)},
|
||||||
|
{"back", Vec3f(0, 0, 800), Vec3f(0, 0, 0)},
|
||||||
|
{"left", Vec3f(-800, 0, 0), Vec3f(0, 0, 0)},
|
||||||
|
{"right", Vec3f(800, 0, 0), Vec3f(0, 0, 0)},
|
||||||
|
{"top", Vec3f(0, 800, 0), Vec3f(0, 0, 0)},
|
||||||
|
{"bottom", Vec3f(0, -800, 0), Vec3f(0, 0, 0)},
|
||||||
|
|
||||||
|
// 45° angle views
|
||||||
|
{"front_right_top", Vec3f(800, 800, -800), Vec3f(0, 0, 0)},
|
||||||
|
{"front_left_top", Vec3f(-800, 800, -800), Vec3f(0, 0, 0)},
|
||||||
|
{"front_right_bottom", Vec3f(800, -800, -800), Vec3f(0, 0, 0)},
|
||||||
|
{"front_left_bottom", Vec3f(-800, -800, -800), Vec3f(0, 0, 0)},
|
||||||
|
|
||||||
|
{"back_right_top", Vec3f(800, 800, 800), Vec3f(0, 0, 0)},
|
||||||
|
{"back_left_top", Vec3f(-800, 800, 800), Vec3f(0, 0, 0)},
|
||||||
|
{"back_right_bottom", Vec3f(800, -800, 800), Vec3f(0, 0, 0)},
|
||||||
|
{"back_left_bottom", Vec3f(-800, -800, 800), Vec3f(0, 0, 0)},
|
||||||
|
|
||||||
|
// Additional interesting angles
|
||||||
|
{"diagonal_xy", Vec3f(800, 800, 0), Vec3f(0, 0, 0)},
|
||||||
|
{"diagonal_xz", Vec3f(800, 0, 800), Vec3f(0, 0, 0)},
|
||||||
|
{"diagonal_yz", Vec3f(0, 800, 800), Vec3f(0, 0, 0)},
|
||||||
|
|
||||||
|
// Isometric-like views
|
||||||
|
{"isometric_1", Vec3f(600, 600, 600), Vec3f(0, 0, 0)},
|
||||||
|
{"isometric_2", Vec3f(-600, 600, 600), Vec3f(0, 0, 0)},
|
||||||
|
{"isometric_3", Vec3f(600, -600, 600), Vec3f(0, 0, 0)},
|
||||||
|
{"isometric_4", Vec3f(-600, -600, 600), Vec3f(0, 0, 0)}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render and save from each angle
|
||||||
|
std::cout << "Rendering from multiple angles..." << std::endl;
|
||||||
|
int saved_count = 0;
|
||||||
|
|
||||||
|
for (const auto& view : view_angles) {
|
||||||
|
// Create view ray
|
||||||
|
Vec3f direction = (view.look_at - view.eye_position).normalized();
|
||||||
|
Ray3<float> view_ray(view.eye_position, direction);
|
||||||
|
|
||||||
|
// Render the frame
|
||||||
|
auto frame = Grid3View::render_region(
|
||||||
|
grid,
|
||||||
|
render_min,
|
||||||
|
render_max,
|
||||||
|
resolution,
|
||||||
|
view_ray,
|
||||||
|
[&](size_t id) { return components.get_color(id); },
|
||||||
|
frame::colormap::RGBA,
|
||||||
|
Vec4ui8(0, 0, 0, 255) // Black background
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save the rendered frame
|
||||||
|
std::string filename = "output/view_" + view.name + ".bmp";
|
||||||
|
bool saved = save_frame(frame, filename);
|
||||||
|
|
||||||
|
if (saved) {
|
||||||
|
saved_count++;
|
||||||
|
std::cout << "Saved: " << filename << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Failed to save: " << filename << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\nSuccessfully saved " << saved_count << " out of " << view_angles.size()
|
||||||
|
<< " views to output/" << std::endl;
|
||||||
|
|
||||||
|
// Optional: Save a summary image with grid statistics
|
||||||
|
std::cout << "\nGrid statistics:" << std::endl;
|
||||||
|
std::cout << "Total positions: " << grid.size() << std::endl;
|
||||||
|
std::cout << "Bounds: [" << min_pos << "] to [" << max_pos << "]" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user