woops
This commit is contained in:
1
glm
Submodule
1
glm
Submodule
Submodule glm added at 8f6213d379
322
latlonv.cpp
322
latlonv.cpp
@@ -1,322 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user