tim.bliss Posted August 9, 2021 Share Posted August 9, 2021 Where can I find the export map button? Link to comment
silent Posted August 9, 2021 Share Posted August 9, 2021 Hi Tim, Export was available in the past for the very simple ObjectTerrain. Right now there is no export heights available in the Editor (mostly because of the very high height density that is being calculated on GPU). It's not that easy to export such highly detailed data. You can write your own simplified export that will fit your project's needs via C++ / C# API. You can also check C++ Samples project in SDK Browser -> Samples -> Demos -> C++ Samples -> Landscape Terrain -> Mesh - it shows how to convert heights to mesh (but you can also do a heights -> texture / image conversion on your side as well). Thanks! How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN Link to comment
romain.janil Posted October 16, 2021 Share Posted October 16, 2021 (edited) HI, I need to export a mesh out of a landscape (the old one not landscapeTerrainObject) out of 2.13.0.1, how would this be possible ? I can't find the sample for 2.13.0.1 only for 2.14.+ ... Edited October 16, 2021 by romain.janil Link to comment
silent Posted October 18, 2021 Share Posted October 18, 2021 We have some old snippet from 2.10 (or earlier versions). Some adjustments for this code for sure would be required: #include "AppSystemLogic.h" #include <UnigineApp.h> #include <UnigineConsole.h> #include <UnigineFileSystem.h> #include <UnigineGame.h> #include <UnigineWorld.h> #include <UnigineEditor.h> #include <UnigineTilesetFile.h> using namespace Unigine; using namespace Math; // System logic, it exists during the application life cycle. // These methods are called right after corresponding system script's (UnigineScript) methods. AppSystemLogic::AppSystemLogic() { } AppSystemLogic::~AppSystemLogic() { } void make_mesh_terrain(int argc, char **argv) { int lod = 1; ObjectTerrainGlobalPtr terrain; if (argc == 1) { int num_terrain = 0; Vector<NodePtr> nodes; World::get()->getNodes(nodes); for (auto & it : nodes) { if (it->getType() == Node::OBJECT_TERRAIN_GLOBAL) { terrain = ObjectTerrainGlobal::cast(it); Log::message("\t%d terrain: '%s'\n", num_terrain++, terrain->getName()); } } } else if (argc == 2) { String terrain_name= argv[1]; terrain = ObjectTerrainGlobal::cast(Editor::get()->getNodeByName(terrain_name.get())); } else { return; } if (!terrain) { Log::error("cant find terrain!\n"); return; } Log::message("current terrain %s\n", terrain->getName()); int tileres = terrain->getHeightLods()->getLod(lod)->getTileset()->getTileResolution(); //128 float tile_density = terrain->getHeightLods()->getLod(lod)->getTileset()->getTileDensity(); // 104.23116 float tile_size = terrain->getHeightLods()->getLod(lod)->getTileset()->getTileSize(); // 13341.5888 String path = terrain->getHeightLods()->getLod(lod)->getTileset()->getPath(); // "ladscapeBugulmaWinter/heights/lod1/" int count_tiles_x = 1; int count_tiles_y = 1; TilesetFilePtr tf = TilesetFile::create(); if (tf->load((path + "data").get())) { int maxx = 0; int maxy = 0; int minx = 0; int miny = 0; for (int i = 0 ; i < tf->getNumTiles(); i++) { int x, y; tf->getTilePos(i, x, y); maxx = max(maxx, x); maxy = max(maxy, y); minx = min(minx, x); miny = min(miny, y); } count_tiles_x = maxx - minx + 1; count_tiles_y = maxy - miny + 1; } float step_x = tile_density; float step_y = step_x; float size_x = tile_size * count_tiles_x; float size_y = tile_size * count_tiles_y; Log::message("lasdscape %s: density %f, size %f x %f\n", terrain->getName(), step_x, size_x, size_y); ObjectMeshDynamicPtr mesh = ObjectMeshDynamic::create(); mesh->setMaterial("mesh_base", "*"); // allocate space in index and vertex buffers int count_x = size_x/step_x; int count_y = size_y/step_y; terrain->setForceIntersection(1); mesh->allocateVertex(count_x * count_y); mesh->allocateIndices(((count_x-1) * 2 * (count_y-1)) * 3); for (int i = 0 ; i < count_x; i++) { float x = i * step_x - (count_x * step_x * 0.5f); for (int j = 0; j < count_y; j++) { float y = j * step_y - (count_y * step_y * 0.5f); Vec3 point; vec3 normal; vec3 up; if (terrain->fetchTopologyData(x, y, point, normal, up, 1)) mesh->addVertex(vec3(point)); else { vec3 p1 = vec3(x, y, 10000); vec3 p2 = vec3(x, y, -10000); vec4 texcord; vec3 retpoint; int index, inst, surf; if (terrain->getIntersection(p1, p2, ~0, &retpoint, &normal, &texcord, &index, &inst, &surf)) { mesh->addVertex(retpoint); } else mesh->addVertex(vec3(x, y, 0)); } } } for (int i = 0; i < count_x-1; i++) { for (int j = 0 ; j < count_y-1; j++) { mesh->addIndex((i*count_x) + j); // 0 mesh->addIndex((i+1) * count_x + j + 1); //4 mesh->addIndex((i*count_x) + j + 1); // 1 mesh->addIndex((i*count_x) + j); //0 mesh->addIndex((i+1) * count_x + j); // 3 mesh->addIndex((i+1) * count_x + j + 1); // 4 } } // calculate tangent vectors mesh->updateTangents(); // optimize vertex and index buffers, if necessary // mesh->updateIndices(); // calculate a mesh bounding box mesh->updateBounds(); String name = String::format("%s_%s.mesh", World::get()->getName(), terrain->getName()); mesh->saveMesh(name.get()); Log::message("mesh saved to %s (%d vertex)\n", name.get(), mesh->getNumVertex()); } int AppSystemLogic::init() { Console::get()->addCommand("create_mesh_terrain","", MakeCallback(&make_mesh_terrain)); return 1; } If you have very dense elevation grid it may not be saved correctly. How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN Link to comment
romain.janil Posted October 18, 2021 Share Posted October 18, 2021 thx for the snippet I'll give it a try Link to comment
romain.janil Posted October 18, 2021 Share Posted October 18, 2021 Hi Silent, tried to add code to my AppSystemLogic but get an unkown command "create_mesh_terrain" while running app any clue? Link to comment
silent Posted October 19, 2021 Share Posted October 19, 2021 Hard to tell. Have you tried to compile this code after adding? How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN Link to comment
romain.janil Posted October 19, 2021 Share Posted October 19, 2021 doesn't compile in 2.13 , have really little time to investigate, would you be so kind to check what's wrong with code in 2.13 (i would have only this code in default project, just to see if I'm able to export a terrainGlobal as mesh) Link to comment
cash-metall Posted October 19, 2021 Share Posted October 19, 2021 Hi! here is snippet for 2.13 version // somewhere in AppSystemLogic.cpp void create_mesh_terrain(int argc, char** argv) { int lod = 1; ObjectTerrainGlobalPtr terrain; if (argc == 1) { int num_terrain = 0; Vector<NodePtr> nodes; World::getNodes(nodes); for (auto& it : nodes) { if (it->getType() == Node::OBJECT_TERRAIN_GLOBAL) { terrain = static_ptr_cast<ObjectTerrainGlobal>(it); Log::message("\t%d terrain: '%s'\n", num_terrain++, terrain->getName()); } } } else if (argc == 2) { String terrain_name = argv[1]; terrain = static_ptr_cast<ObjectTerrainGlobal>(World::getNodeByName(terrain_name.get())); } else { return; } if (!terrain) { Log::error("cant find terrain!\n"); return; } Log::message("current terrain %s\n", terrain->getName()); int tileres = terrain->getHeightLods()->getLod(lod)->getTileset()->getTileResolution(); //128 float tile_density = terrain->getHeightLods()->getLod(lod)->getTileset()->getTileDensity(); // 104.23116 float tile_size = terrain->getHeightLods()->getLod(lod)->getTileset()->getTileSize(); // 13341.5888 String path = terrain->getHeightLods()->getLod(lod)->getTileset()->getPath(); int count_tiles_x = 1; int count_tiles_y = 1; TilesetFilePtr tf = TilesetFile::create(); if (tf->load((path + "data").get())) { int maxx = 0; int maxy = 0; int minx = 0; int miny = 0; for (int i = 0; i < tf->getNumTiles(); i++) { int x, y; tf->getTilePos(i, x, y); maxx = max(maxx, x); maxy = max(maxy, y); minx = min(minx, x); miny = min(miny, y); } count_tiles_x = maxx - minx + 1; count_tiles_y = maxy - miny + 1; } float step_x = tile_density; float step_y = step_x; float size_x = tile_size * count_tiles_x; float size_y = tile_size * count_tiles_y; Log::message("lasdscape %s: density %f, size %f x %f\n", terrain->getName(), step_x, size_x, size_y); ObjectMeshDynamicPtr mesh = ObjectMeshDynamic::create(); mesh->setMaterial("mesh_base", "*"); // allocate space in index and vertex buffers int count_x = size_x / step_x; int count_y = size_y / step_y; terrain->setForceIntersection(1); mesh->allocateVertex(count_x * count_y); mesh->allocateIndices(((count_x - 1) * 2 * (count_y - 1)) * 3); for (int i = 0; i < count_x; i++) { float x = i * step_x - (count_x * step_x * 0.5f); for (int j = 0; j < count_y; j++) { float y = j * step_y - (count_y * step_y * 0.5f); Vec3 point; vec3 normal; vec3 up; if (terrain->fetchTopologyData(x, y, point, normal, up, 1)) mesh->addVertex(vec3(point)); else { Vec3 p1 = Vec3(x, y, 10000); Vec3 p2 = Vec3(x, y, -10000); vec4 texcord; Vec3 retpoint; int index, inst, surf; if (terrain->getIntersection(p1, p2, ~0, &retpoint, &normal, &texcord, &index, &inst, &surf)) { mesh->addVertex(vec3(retpoint)); } else mesh->addVertex(vec3(x, y, 0)); } } } for (int i = 0; i < count_x - 1; i++) { for (int j = 0; j < count_y - 1; j++) { mesh->addIndex((i * count_x) + j); // 0 mesh->addIndex((i + 1) * count_x + j + 1); //4 mesh->addIndex((i * count_x) + j + 1); // 1 mesh->addIndex((i * count_x) + j); //0 mesh->addIndex((i + 1) * count_x + j); // 3 mesh->addIndex((i + 1) * count_x + j + 1); // 4 } } // calculate tangent vectors mesh->updateTangents(); // optimize vertex and index buffers, if necessary // mesh->updateIndices(); // calculate a mesh bounding box mesh->updateBounds(); String name = String::format("%s_%s.mesh", World::getPath(), terrain->getName()); mesh->saveMesh(name.get()); Log::message("mesh saved to %s (%d vertex)\n", name.get(), mesh->getNumVertex()); } // in AppSystemLogic::init(): Console::addCommand("create_mesh_terrain", "\ncreate_mesh_terrain [nameofterrain] - export terrain to mesh file. \nif 'nameofterrain' is empty - the first one is chosen\n", MakeCallback(&create_mesh_terrain)); 3 Link to comment
romain.janil Posted October 19, 2021 Share Posted October 19, 2021 (edited) thanks, a lot ! Edited October 19, 2021 by romain.janil Link to comment
romain.janil Posted October 19, 2021 Share Posted October 19, 2021 it works...but crashes the engine while processing on a very large terrainGlobal (density around 50)... Link to comment
silent Posted October 19, 2021 Share Posted October 19, 2021 If you have very big terrain you would need to export it as a grid of meshes. Provided snippet is just a proof of concept that you need to tune for your needs. Regular mesh precision is float, so there is no really point to store anything bigger than 10x10km inside it. How to submit a good bug report --- FTP server for test scenes and user uploads: ftp://files.unigine.com user: upload password: 6xYkd6vLYWjpW6SN Link to comment
Recommended Posts