SRTM example: use nodes & load height data in a bg thread
This commit is contained in:
parent
1771f56508
commit
a09eccdf0c
1 changed files with 368 additions and 239 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
#include <psemek/gfx/mesh.hpp>
|
#include <psemek/gfx/mesh.hpp>
|
||||||
#include <psemek/gfx/program.hpp>
|
#include <psemek/gfx/program.hpp>
|
||||||
#include <psemek/gfx/painter.hpp>
|
#include <psemek/gfx/painter.hpp>
|
||||||
|
#include <psemek/gfx/error.hpp>
|
||||||
|
|
||||||
#include <psemek/geom/camera.hpp>
|
#include <psemek/geom/camera.hpp>
|
||||||
#include <psemek/geom/math.hpp>
|
#include <psemek/geom/math.hpp>
|
||||||
|
|
@ -25,6 +26,13 @@
|
||||||
#include <psemek/util/to_string.hpp>
|
#include <psemek/util/to_string.hpp>
|
||||||
#include <psemek/util/moving_average.hpp>
|
#include <psemek/util/moving_average.hpp>
|
||||||
#include <psemek/util/recursive.hpp>
|
#include <psemek/util/recursive.hpp>
|
||||||
|
#include <psemek/util/threadpool.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <atomic>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
using namespace psemek;
|
using namespace psemek;
|
||||||
|
|
||||||
|
|
@ -59,141 +67,147 @@ private:
|
||||||
T speed_;
|
T speed_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static char const tile_vs[] =
|
struct height_provider
|
||||||
R"(#version 330
|
|
||||||
|
|
||||||
uniform mat4 u_transform;
|
|
||||||
|
|
||||||
uniform int u_icosa_face;
|
|
||||||
uniform int u_N;
|
|
||||||
uniform vec3 u_p0;
|
|
||||||
uniform vec3 u_p1;
|
|
||||||
uniform vec3 u_p2;
|
|
||||||
uniform vec4 u_color;
|
|
||||||
|
|
||||||
out vec3 color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
{
|
||||||
int i = int(floor(0.5 * (sqrt(1.0 + 8.0 * gl_VertexID) - 1.0)));
|
float height_at(geom::vector<float, 3> const & v);
|
||||||
int j = gl_VertexID - (i * (i + 1)) / 2;
|
|
||||||
|
|
||||||
float t0 = 1.0 - float(i) / float(u_N);
|
struct datum_id_hash
|
||||||
float t1 = float(j) / float(u_N);
|
|
||||||
float t2 = 1.0 - t0 - t1;
|
|
||||||
|
|
||||||
vec3 p = normalize(u_p0 * t0 + u_p1 * t1 + u_p2 * t2);
|
|
||||||
gl_Position = u_transform * vec4(p, 1.0);
|
|
||||||
color = u_color.rgb;
|
|
||||||
})";
|
|
||||||
|
|
||||||
static char const tile_fs[] =
|
|
||||||
R"(#version 330
|
|
||||||
|
|
||||||
in vec3 color;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
out_color = vec4(color, 1.0);
|
|
||||||
})";
|
|
||||||
|
|
||||||
static char const test_vs[] =
|
|
||||||
R"(#version 330
|
|
||||||
|
|
||||||
uniform mat4 u_transform;
|
|
||||||
|
|
||||||
layout (location = 0) in vec4 in_position;
|
|
||||||
|
|
||||||
out vec4 color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = u_transform * in_position;
|
|
||||||
color = vec4(in_position.xyz * 0.5 + vec3(0.5), 1.0);
|
|
||||||
})";
|
|
||||||
|
|
||||||
static char const test_fs[] =
|
|
||||||
R"(#version 330
|
|
||||||
|
|
||||||
in vec4 color;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
out_color = color;
|
|
||||||
})";
|
|
||||||
|
|
||||||
struct srtm_app
|
|
||||||
: app::app
|
|
||||||
{
|
|
||||||
srtm_app();
|
|
||||||
|
|
||||||
void on_resize(int width, int height) override;
|
|
||||||
|
|
||||||
void on_mouse_move(int x, int y, int dx, int dy) override;
|
|
||||||
|
|
||||||
void update() override;
|
|
||||||
void present() override;
|
|
||||||
|
|
||||||
// geom::spherical_camera camera;
|
|
||||||
geom::free_camera camera;
|
|
||||||
smooth_updater<float, float> camera_azimuthal_angle_updater{camera.azimuthal_angle, 20.f};
|
|
||||||
smooth_updater<float, float> camera_elevation_angle_updater{camera.elevation_angle, 20.f};
|
|
||||||
bool camera_forward = false;
|
|
||||||
|
|
||||||
static constexpr int tile_size_log2 = 8;
|
|
||||||
static constexpr int tile_size = (1 << tile_size_log2);
|
|
||||||
|
|
||||||
gfx::mesh tile_mesh[tile_size_log2 + 1];
|
|
||||||
|
|
||||||
gfx::program tile_program{tile_vs, tile_fs};
|
|
||||||
gfx::program test_program{test_vs, test_fs};
|
|
||||||
|
|
||||||
gfx::mesh test_mesh;
|
|
||||||
|
|
||||||
struct test_object
|
|
||||||
{
|
{
|
||||||
cg::box<float, 3> body;
|
std::size_t operator() (std::pair<int, int> const & p) const
|
||||||
gfx::mesh mesh;
|
{
|
||||||
int x, y;
|
return ((p.first + 180) << 16) | (p.second + 90);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int const test_object_count = 21;
|
std::unordered_map<std::pair<int, int>, std::unique_ptr<std::int16_t[]>, datum_id_hash> datums;
|
||||||
std::vector<test_object> test_objects;
|
std::unordered_set<std::pair<int, int>, datum_id_hash> no_datums;
|
||||||
|
|
||||||
util::clock<std::chrono::duration<float>> frame_clock;
|
|
||||||
util::moving_average<float> frame_dt_average{32};
|
|
||||||
|
|
||||||
gfx::painter painter;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
srtm_app::srtm_app()
|
static geom::interval<int> height_range;
|
||||||
: app("SRTM", 4)
|
|
||||||
|
float height_provider::height_at(geom::vector<float, 3> const & v)
|
||||||
{
|
{
|
||||||
vsync(false);
|
static std::string const data_path = "/home/lisyarus/data/srtm/dem-unpacked/";
|
||||||
show_cursor(false);
|
|
||||||
|
|
||||||
camera.fov_y = geom::rad(45.f);
|
float const lat = geom::deg(std::asin(v[2]));
|
||||||
camera.near_clip = 0.0001f;
|
|
||||||
camera.far_clip = 10.f;
|
|
||||||
// camera.target = {0.f, 0.f, 0.f};
|
|
||||||
camera.pos = {0.f, -10.f, 0.f};
|
|
||||||
camera.azimuthal_angle = 0.f;
|
|
||||||
camera.elevation_angle = 0.f;
|
|
||||||
// camera.distance = 5.f;
|
|
||||||
|
|
||||||
camera_azimuthal_angle_updater = camera.azimuthal_angle;
|
if (std::abs(lat) > 60.f) return 0.f;
|
||||||
camera_elevation_angle_updater = camera.elevation_angle;
|
return -10.f;
|
||||||
// camera_distance_updater = camera.distance;
|
|
||||||
|
|
||||||
for (std::size_t N = 0; N <= tile_size_log2; ++N)
|
float const lon = geom::deg(std::atan2(v[0], -v[1]));
|
||||||
|
|
||||||
|
int ilat = std::floor(lat);
|
||||||
|
int ilon = std::floor(lon);
|
||||||
|
|
||||||
|
auto id = std::make_pair(ilat, ilon);
|
||||||
|
|
||||||
|
if (no_datums.count(id) > 0)
|
||||||
|
return -10.f;
|
||||||
|
|
||||||
|
if (datums.count(id) == 0)
|
||||||
{
|
{
|
||||||
std::vector<std::uint16_t> indices;
|
if (datums.size() > 40)
|
||||||
|
datums.clear();
|
||||||
|
|
||||||
std::size_t step = tile_size / (1 << N);
|
std::ostringstream os;
|
||||||
|
if (ilat >= 0)
|
||||||
|
os << 'N' << std::setw(2) << std::setfill('0') << ilat;
|
||||||
|
else
|
||||||
|
os << 'S' << std::setw(2) << std::setfill('0') << (-ilat);
|
||||||
|
if (ilon >= 0)
|
||||||
|
os << 'E' << std::setw(3) << std::setfill('0') << ilon;
|
||||||
|
else
|
||||||
|
os << 'W' << std::setw(3) << std::setfill('0') << (-ilon);
|
||||||
|
|
||||||
auto idx = [step](std::size_t i, std::size_t j) -> std::uint16_t
|
os << ".hgt";
|
||||||
|
|
||||||
|
std::string const filename = data_path + os.str();
|
||||||
|
std::ifstream ifs(filename, std::ios::binary);
|
||||||
|
|
||||||
|
if (!ifs)
|
||||||
|
{
|
||||||
|
no_datums.insert(id);
|
||||||
|
return -10.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 10.f;
|
||||||
|
|
||||||
|
std::unique_ptr<std::int16_t[]> values{new std::int16_t[3601 * 3601]};
|
||||||
|
ifs.read(reinterpret_cast<char *>(values.get()), 3601 * 3601 * 2);
|
||||||
|
datums[id] = std::move(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const * values = datums[id].get();
|
||||||
|
|
||||||
|
int const tlat = geom::clamp<int>(std::round((lat - ilat) * 3600), {0, 3600});
|
||||||
|
int const tlon = geom::clamp<int>(std::round((lon - ilon) * 3600), {0, 3600});
|
||||||
|
|
||||||
|
auto h = values[tlat * 3601 + 3600 - tlon];
|
||||||
|
h = ((h & 255) << 8) | (h >> 8);
|
||||||
|
height_range |= (int)h;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node
|
||||||
|
{
|
||||||
|
geom::vector<float, 3> v[3];
|
||||||
|
|
||||||
|
virtual void draw(int level) = 0;
|
||||||
|
virtual node * child(int id) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct node_controller
|
||||||
|
{
|
||||||
|
node_controller();
|
||||||
|
|
||||||
|
node * root(int f);
|
||||||
|
|
||||||
|
std::size_t node_count() const { return node_count_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node_impl
|
||||||
|
: node
|
||||||
|
{
|
||||||
|
node_controller * controller;
|
||||||
|
gfx::array array;
|
||||||
|
gfx::buffer height_buffer;
|
||||||
|
std::unique_ptr<node> children[256];
|
||||||
|
|
||||||
|
std::vector<std::int16_t> height_data;
|
||||||
|
std::atomic<bool> height_data_ready = false;
|
||||||
|
bool height_data_loaded = false;
|
||||||
|
|
||||||
|
void draw(int level) override;
|
||||||
|
node * child(int id) override;
|
||||||
|
|
||||||
|
void load_heights();
|
||||||
|
};
|
||||||
|
|
||||||
|
cg::icosahedron<float> icosahedron_;
|
||||||
|
|
||||||
|
gfx::buffer index_buffer_;
|
||||||
|
std::size_t index_counts_[10];
|
||||||
|
std::unique_ptr<node_impl> roots_[20];
|
||||||
|
|
||||||
|
height_provider height_provider_;
|
||||||
|
|
||||||
|
util::threadpool loader_{"load", 1};
|
||||||
|
|
||||||
|
std::size_t node_count_ = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<node_impl> make_node();
|
||||||
|
};
|
||||||
|
|
||||||
|
node_controller::node_controller()
|
||||||
|
: icosahedron_{geom::point<float, 3>::zero(), 1.f}
|
||||||
|
{
|
||||||
|
std::vector<std::uint32_t> indices;
|
||||||
|
index_counts_[0] = 0;
|
||||||
|
for (std::size_t N = 0; N <= 8; ++N)
|
||||||
|
{
|
||||||
|
std::size_t step = 256 >> N;
|
||||||
|
|
||||||
|
auto idx = [step](std::size_t i, std::size_t j) -> std::uint32_t
|
||||||
{
|
{
|
||||||
i *= step;
|
i *= step;
|
||||||
j *= step;
|
j *= step;
|
||||||
|
|
@ -208,36 +222,229 @@ srtm_app::srtm_app()
|
||||||
indices.push_back(idx(i, j));
|
indices.push_back(idx(i, j));
|
||||||
}
|
}
|
||||||
indices.push_back(idx(i + 1, i + 1));
|
indices.push_back(idx(i + 1, i + 1));
|
||||||
indices.push_back(0xffffu);
|
indices.push_back(0xffffffffu);
|
||||||
}
|
}
|
||||||
|
|
||||||
tile_mesh[N].load_index(indices, gl::TRIANGLE_STRIP, gl::STATIC_DRAW);
|
index_counts_[N + 1] = indices.size();
|
||||||
}
|
}
|
||||||
|
index_buffer_.load(indices, gl::STATIC_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = - test_object_count + 1; x <= test_object_count - 1; x += 2)
|
node * node_controller::root(int f)
|
||||||
|
{
|
||||||
|
if (!roots_[f])
|
||||||
{
|
{
|
||||||
for (int y = - test_object_count + 1; y <= test_object_count - 1; y += 2)
|
auto n = make_node();
|
||||||
{
|
|
||||||
auto & o = test_objects.emplace_back();
|
|
||||||
|
|
||||||
o.x = (x + test_object_count - 1) / 2;
|
auto face = cg::faces(icosahedron_)[f];
|
||||||
o.y = (y + test_object_count - 1) / 2;
|
n->v[0] = icosahedron_.vertices[face[0]] - geom::point<float, 3>::zero();
|
||||||
|
n->v[1] = icosahedron_.vertices[face[1]] - geom::point<float, 3>::zero();
|
||||||
|
n->v[2] = icosahedron_.vertices[face[2]] - geom::point<float, 3>::zero();
|
||||||
|
|
||||||
geom::box<float, 3> b {{
|
n->load_heights();
|
||||||
{x - 1.f, x + 1.f},
|
|
||||||
{y - 1.f, y + 1.f},
|
|
||||||
{0 - 1.f, 0 + 1.f}
|
|
||||||
}};
|
|
||||||
|
|
||||||
o.body = cg::box(b);
|
roots_[f] = std::move(n);
|
||||||
|
|
||||||
auto const & vertices = cg::vertices(o.body);
|
|
||||||
auto const & edges = cg::edges(o.body);
|
|
||||||
|
|
||||||
o.mesh.setup<geom::point<float, 3>>();
|
|
||||||
o.mesh.load(vertices.data(), vertices.size(), edges.data(), edges.size());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return roots_[f].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<node_controller::node_impl> node_controller::make_node()
|
||||||
|
{
|
||||||
|
auto n = std::make_unique<node_controller::node_impl>();
|
||||||
|
|
||||||
|
n->controller = this;
|
||||||
|
n->array.bind();
|
||||||
|
n->height_buffer.bind();
|
||||||
|
gl::EnableVertexAttribArray(0);
|
||||||
|
gl::VertexAttribPointer(0, 1, gl::SHORT, gl::FALSE, 0, nullptr);
|
||||||
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_.id());
|
||||||
|
|
||||||
|
++node_count_;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_controller::node_impl::draw(int level)
|
||||||
|
{
|
||||||
|
if (!height_data_loaded)
|
||||||
|
{
|
||||||
|
if (!height_data_ready) return;
|
||||||
|
|
||||||
|
height_buffer.load(height_data, gl::STATIC_DRAW);
|
||||||
|
height_data.clear();
|
||||||
|
height_data_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
array.bind();
|
||||||
|
std::size_t offset = controller->index_counts_[level];
|
||||||
|
std::size_t count = controller->index_counts_[level + 1] - offset;
|
||||||
|
gl::DrawElements(gl::TRIANGLE_STRIP, count, gl::UNSIGNED_INT, (std::uint32_t const *)(nullptr) + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
node * node_controller::node_impl::child(int id)
|
||||||
|
{
|
||||||
|
if (!children[id])
|
||||||
|
{
|
||||||
|
auto n = controller->make_node();
|
||||||
|
|
||||||
|
int i0, j0, i1, j1, i2, j2;
|
||||||
|
|
||||||
|
if (id < 136)
|
||||||
|
{
|
||||||
|
int i = int(std::floor(0.5f * (sqrt(1.f + 8.f * id) - 1.f)));
|
||||||
|
int j = id - (i * (i + 1)) / 2;
|
||||||
|
|
||||||
|
i0 = i;
|
||||||
|
j0 = j;
|
||||||
|
i1 = i + 1;
|
||||||
|
j1 = j + 1;
|
||||||
|
i2 = i + 1;
|
||||||
|
j2 = j;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i = int(std::floor(0.5f * (sqrt(1.f + 8.f * (id - 136)) - 1.f)));
|
||||||
|
int j = id - 136 - (i * (i + 1)) / 2;
|
||||||
|
|
||||||
|
i0 = i + 1;
|
||||||
|
j0 = j;
|
||||||
|
i1 = i + 1;
|
||||||
|
j1 = j + 1;
|
||||||
|
i2 = i + 2;
|
||||||
|
j2 = j + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto at = [this](int i, int j)
|
||||||
|
{
|
||||||
|
float t0 = 1.f - (1.f * i) / 16.f;
|
||||||
|
float t1 = (1.f * j) / 16.f;
|
||||||
|
float t2 = 1.f - t0 - t1;
|
||||||
|
|
||||||
|
return geom::normalized(v[0] * t0 + v[1] * t1 + v[2] * t2);
|
||||||
|
};
|
||||||
|
|
||||||
|
n->v[0] = at(i0, j0);
|
||||||
|
n->v[1] = at(i1, j1);
|
||||||
|
n->v[2] = at(i2, j2);
|
||||||
|
|
||||||
|
n->load_heights();
|
||||||
|
|
||||||
|
children[id] = std::move(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return children[id].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_controller::node_impl::load_heights()
|
||||||
|
{
|
||||||
|
controller->loader_.dispatch([this]{
|
||||||
|
height_data.assign((257 * 258) / 2, 0);
|
||||||
|
|
||||||
|
auto * out = height_data.data();
|
||||||
|
|
||||||
|
auto at = [this](int i, int j)
|
||||||
|
{
|
||||||
|
float t0 = 1.f - (1.f * i) / 256.f;
|
||||||
|
float t1 = (1.f * j) / 256.f;
|
||||||
|
float t2 = 1.f - t0 - t1;
|
||||||
|
|
||||||
|
return geom::normalized(v[0] * t0 + v[1] * t1 + v[2] * t2);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i <= 256; ++i)
|
||||||
|
{
|
||||||
|
for (int j = 0; j <= i; ++j)
|
||||||
|
{
|
||||||
|
*out++ = static_cast<std::int16_t>(controller->height_provider_.height_at(at(i, j)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
height_data_ready = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static char const tile_vs[] =
|
||||||
|
R"(#version 330
|
||||||
|
|
||||||
|
uniform mat4 u_transform;
|
||||||
|
|
||||||
|
uniform int u_N;
|
||||||
|
uniform vec3 u_p0;
|
||||||
|
uniform vec3 u_p1;
|
||||||
|
uniform vec3 u_p2;
|
||||||
|
|
||||||
|
layout (location = 0) in float in_height;
|
||||||
|
|
||||||
|
out vec3 color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
int i = int(floor(0.5 * (sqrt(1.0 + 8.0 * gl_VertexID) - 1.0)));
|
||||||
|
int j = gl_VertexID - (i * (i + 1)) / 2;
|
||||||
|
|
||||||
|
float t0 = 1.0 - float(i) / float(u_N);
|
||||||
|
float t1 = float(j) / float(u_N);
|
||||||
|
float t2 = 1.0 - t0 - t1;
|
||||||
|
|
||||||
|
vec3 p = normalize(u_p0 * t0 + u_p1 * t1 + u_p2 * t2) * (1.0 + in_height / 6400000.0);
|
||||||
|
gl_Position = u_transform * vec4(p, 1.0);
|
||||||
|
color = (in_height < 0.0) ? vec3(0.0, 0.0, 0.5) : vec3(0.0, 0.5, 0.0);
|
||||||
|
})";
|
||||||
|
|
||||||
|
static char const tile_fs[] =
|
||||||
|
R"(#version 330
|
||||||
|
|
||||||
|
in vec3 color;
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
out_color = vec4(color, 1.0);
|
||||||
|
})";
|
||||||
|
|
||||||
|
struct srtm_app
|
||||||
|
: app::app
|
||||||
|
{
|
||||||
|
srtm_app();
|
||||||
|
|
||||||
|
void on_resize(int width, int height) override;
|
||||||
|
|
||||||
|
void on_mouse_move(int x, int y, int dx, int dy) override;
|
||||||
|
|
||||||
|
void update() override;
|
||||||
|
void present() override;
|
||||||
|
|
||||||
|
geom::free_camera camera;
|
||||||
|
smooth_updater<float, float> camera_azimuthal_angle_updater{camera.azimuthal_angle, 20.f};
|
||||||
|
smooth_updater<float, float> camera_elevation_angle_updater{camera.elevation_angle, 20.f};
|
||||||
|
bool camera_forward = false;
|
||||||
|
|
||||||
|
node_controller nodes;
|
||||||
|
|
||||||
|
gfx::program tile_program{tile_vs, tile_fs};
|
||||||
|
|
||||||
|
util::clock<std::chrono::duration<float>> frame_clock;
|
||||||
|
util::moving_average<float> frame_dt_average{32};
|
||||||
|
|
||||||
|
gfx::painter painter;
|
||||||
|
};
|
||||||
|
|
||||||
|
srtm_app::srtm_app()
|
||||||
|
: app("SRTM", 4)
|
||||||
|
{
|
||||||
|
vsync(true);
|
||||||
|
show_cursor(false);
|
||||||
|
|
||||||
|
camera.fov_y = geom::rad(45.f);
|
||||||
|
camera.near_clip = 0.0001f;
|
||||||
|
camera.far_clip = 10.f;
|
||||||
|
camera.pos = {0.f, -10.f, 0.f};
|
||||||
|
camera.azimuthal_angle = 0.f;
|
||||||
|
camera.elevation_angle = 0.f;
|
||||||
|
|
||||||
|
camera_azimuthal_angle_updater = camera.azimuthal_angle;
|
||||||
|
camera_elevation_angle_updater = camera.elevation_angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void srtm_app::on_resize(int width, int height)
|
void srtm_app::on_resize(int width, int height)
|
||||||
|
|
@ -342,14 +549,14 @@ void srtm_app::present()
|
||||||
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
|
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
gl::LineWidth(2.f);
|
gl::LineWidth(2.f);
|
||||||
gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
|
gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
|
||||||
gl::PointSize(5.f);
|
gl::PointSize(5.f);
|
||||||
gl::Enable(gl::CULL_FACE);
|
gl::Enable(gl::CULL_FACE);
|
||||||
gl::Enable(gl::DEPTH_TEST);
|
gl::Enable(gl::DEPTH_TEST);
|
||||||
gl::DepthFunc(gl::LEQUAL);
|
gl::DepthFunc(gl::LEQUAL);
|
||||||
|
|
||||||
gl::Enable(gl::PRIMITIVE_RESTART);
|
gl::Enable(gl::PRIMITIVE_RESTART);
|
||||||
gl::PrimitiveRestartIndex(0xffffu);
|
gl::PrimitiveRestartIndex(0xffffffffu);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto d = geom::distance(camera.pos, geom::point<float, 3>::zero());
|
auto d = geom::distance(camera.pos, geom::point<float, 3>::zero());
|
||||||
|
|
@ -359,22 +566,24 @@ void srtm_app::present()
|
||||||
|
|
||||||
auto const camera_transform = camera.transform();
|
auto const camera_transform = camera.transform();
|
||||||
auto const camera_pos = camera.position();
|
auto const camera_pos = camera.position();
|
||||||
auto const camera_direction = camera.direction();
|
// auto const camera_direction = camera.direction();
|
||||||
|
|
||||||
info.push_back(util::to_string("Camera height: ", (geom::distance(camera_pos, geom::point<float, 3>::zero()) - 1.f) * 6400000.f, " m"));
|
info.push_back(util::to_string("Camera height: ", (geom::distance(camera_pos, geom::point<float, 3>::zero()) - 1.f) * 6400000.f, " m"));
|
||||||
|
|
||||||
auto const frustum = cg::frustum(camera_transform);
|
auto const frustum = cg::frustum(camera_transform);
|
||||||
|
(void)frustum;
|
||||||
|
|
||||||
tile_program.bind();
|
tile_program.bind();
|
||||||
tile_program["u_transform"] = camera_transform;
|
tile_program["u_transform"] = camera_transform;
|
||||||
tile_program["u_N"] = static_cast<int>(tile_size);
|
tile_program["u_N"] = static_cast<int>(256);
|
||||||
|
|
||||||
info.push_back(util::to_string("Camera pos: ", camera_pos));
|
info.push_back(util::to_string("Camera pos: ", camera_pos));
|
||||||
|
|
||||||
std::size_t rendered_tiles = 0;
|
std::size_t rendered_tiles = 0;
|
||||||
std::vector<std::size_t> id;
|
std::vector<std::size_t> id;
|
||||||
auto visit = util::recursive([&](auto & self, geom::vector<float, 3> const (&v)[3], int level = 0) -> void
|
auto visit = util::recursive([&](auto & self, node * n, int level = 0) -> void
|
||||||
{
|
{
|
||||||
|
auto const & v = n->v;
|
||||||
auto const o = geom::point<float, 3>::zero();
|
auto const o = geom::point<float, 3>::zero();
|
||||||
auto m = (v[0] + v[1] + v[2]) / 3.f;
|
auto m = (v[0] + v[1] + v[2]) / 3.f;
|
||||||
m = geom::normalized(m) * (1.f + 1.f / 6400.f) - m;
|
m = geom::normalized(m) * (1.f + 1.f / 6400.f) - m;
|
||||||
|
|
@ -400,7 +609,7 @@ void srtm_app::present()
|
||||||
if (cg::separation(body, frustum).second > 0.f)
|
if (cg::separation(body, frustum).second > 0.f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool const selected = geom::intersect(geom::ray{camera_pos, camera_direction}, t);
|
// bool const selected = false && geom::intersect(geom::ray{camera_pos, camera_direction}, t);
|
||||||
|
|
||||||
float on_screen_unit;
|
float on_screen_unit;
|
||||||
|
|
||||||
|
|
@ -433,51 +642,20 @@ void srtm_app::present()
|
||||||
|
|
||||||
assert(on_screen_unit > 0.f);
|
assert(on_screen_unit > 0.f);
|
||||||
|
|
||||||
float const max_triangle_size = 10.f; // pixels
|
float const max_triangle_size = 5.f; // pixels
|
||||||
|
|
||||||
float const side_length = icosa_side / (1 << (level * 4));
|
float const side_length = icosa_side / (1 << (level * 4));
|
||||||
|
|
||||||
int tile_n = std::ceil(std::log2(on_screen_unit * side_length / max_triangle_size));
|
int tile_n = std::ceil(std::log2(on_screen_unit * side_length / max_triangle_size));
|
||||||
|
|
||||||
if (level < 3 && tile_n > tile_size_log2)
|
if (level < 3 && tile_n > 8)
|
||||||
{
|
{
|
||||||
std::size_t const C = 16;
|
for (int id = 0; id < 256; ++id)
|
||||||
|
self(n->child(id), level + 1);
|
||||||
auto at = [&](std::size_t i, std::size_t j)
|
|
||||||
{
|
|
||||||
float t0 = 1.f - (1.f * i) / C;
|
|
||||||
float t1 = (1.f * j) / C;
|
|
||||||
float t2 = 1.f - t0 - t1;
|
|
||||||
|
|
||||||
return geom::normalized(v[0] * t0 + v[1] * t1 + v[2] * t2);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::size_t child_id = 0;
|
|
||||||
|
|
||||||
auto child = [&](std::size_t i0, std::size_t j0, std::size_t i1, std::size_t j1, std::size_t i2, std::size_t j2)
|
|
||||||
{
|
|
||||||
geom::vector<float, 3> v[3];
|
|
||||||
v[0] = at(i0, j0);
|
|
||||||
v[1] = at(i1, j1);
|
|
||||||
v[2] = at(i2, j2);
|
|
||||||
id.push_back(child_id++);
|
|
||||||
self(v, level + 1);
|
|
||||||
id.pop_back();
|
|
||||||
};
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < C; ++i)
|
|
||||||
{
|
|
||||||
for (std::size_t j = 0; j < i; ++j)
|
|
||||||
{
|
|
||||||
child(i + 1, j, i, j, i + 1, j + 1);
|
|
||||||
child(i + 1, j + 1, i, j, i, j + 1);
|
|
||||||
}
|
|
||||||
child(i + 1, i, i, i, i + 1, i + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tile_n = geom::clamp(tile_n, {0, tile_size_log2});
|
tile_n = geom::clamp(tile_n, {0, 8});
|
||||||
|
|
||||||
++rendered_tiles;
|
++rendered_tiles;
|
||||||
|
|
||||||
|
|
@ -494,74 +672,25 @@ void srtm_app::present()
|
||||||
tile_program["u_p2"] = v[2];
|
tile_program["u_p2"] = v[2];
|
||||||
tile_program["u_color"] = colors[tile_n % 4];
|
tile_program["u_color"] = colors[tile_n % 4];
|
||||||
|
|
||||||
tile_mesh[tile_n].draw();
|
n->draw(tile_n);
|
||||||
|
|
||||||
if (selected)
|
|
||||||
{
|
|
||||||
gl::Disable(gl::DEPTH_TEST);
|
|
||||||
tile_program["u_color"] = gfx::white.as_color_4f();
|
|
||||||
tile_mesh[0].draw();
|
|
||||||
gl::Enable(gl::DEPTH_TEST);
|
|
||||||
|
|
||||||
info.push_back(util::to_string("Selected id: ", id));
|
|
||||||
info.push_back(util::to_string("Selected separation: ", cg::separation(body, frustum).second));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// if(false)
|
gfx::check_error();
|
||||||
// for (int f = 4; f < 5; ++f)
|
|
||||||
for (int f = 0; f < 20; ++f)
|
for (int f = 0; f < 20; ++f)
|
||||||
{
|
{
|
||||||
geom::vector<float, 3> v[3];
|
visit(nodes.root(f));
|
||||||
v[0] = icosa_vertices[icosa_faces[f][0]] - geom::point<float, 3>::zero();
|
|
||||||
v[1] = icosa_vertices[icosa_faces[f][1]] - geom::point<float, 3>::zero();
|
|
||||||
v[2] = icosa_vertices[icosa_faces[f][2]] - geom::point<float, 3>::zero();
|
|
||||||
id.push_back(f);
|
|
||||||
visit(v);
|
|
||||||
id.pop_back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info.push_back(util::to_string("Tiles: ", rendered_tiles));
|
info.push_back(util::to_string("Tiles: ", rendered_tiles));
|
||||||
|
|
||||||
if (false)
|
|
||||||
{
|
|
||||||
gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL);
|
|
||||||
gl::Disable(gl::CULL_FACE);
|
|
||||||
|
|
||||||
test_program.bind();
|
|
||||||
test_program["u_transform"] = camera_transform;
|
|
||||||
int visible_count = 0;
|
|
||||||
for (auto const & o : test_objects)
|
|
||||||
{
|
|
||||||
gfx::color_rgba color;
|
|
||||||
|
|
||||||
if (cg::separation(o.body, frustum).second < 0.f)
|
|
||||||
{
|
|
||||||
++visible_count;
|
|
||||||
o.mesh.draw();
|
|
||||||
|
|
||||||
color = gfx::red;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
color = gfx::black;
|
|
||||||
}
|
|
||||||
|
|
||||||
float sx = width() - 10 * test_object_count + o.x * 10;
|
|
||||||
float sy = height() - 10 * test_object_count + (test_object_count - 1 - o.y) * 10;
|
|
||||||
|
|
||||||
painter.rect({{{sx, sx + 10.f}, {sy, sy + 10.f}}}, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
info.push_back(util::to_string("Visible count: ", visible_count));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
float s = 10.f;
|
float s = 10.f;
|
||||||
painter.line({width() / 2.f - s, height() / 2.f}, {width() / 2.f + s, height() / 2.f}, 3.f, gfx::cyan, false);
|
painter.line({width() / 2.f - s, height() / 2.f}, {width() / 2.f + s, height() / 2.f}, 3.f, gfx::cyan, false);
|
||||||
painter.line({width() / 2.f, height() / 2.f - s}, {width() / 2.f, height() / 2.f + s}, 3.f, gfx::cyan, false);
|
painter.line({width() / 2.f, height() / 2.f - s}, {width() / 2.f, height() / 2.f + s}, 3.f, gfx::cyan, false);
|
||||||
}
|
}
|
||||||
|
info.push_back(util::to_string("Heights: ", height_range));
|
||||||
|
info.push_back(util::to_string("Nodes: ", nodes.node_count()));
|
||||||
|
|
||||||
{
|
{
|
||||||
info.insert(info.begin(), util::to_string("FPS: ", 1.f / frame_dt_average.average()));
|
info.insert(info.begin(), util::to_string("FPS: ", 1.f / frame_dt_average.average()));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue