Primitive occulision
This commit is contained in:
parent
c584a79908
commit
e7d34b82be
4
TODO.md
4
TODO.md
|
@ -91,6 +91,6 @@
|
|||
- [x] Chunk size performance
|
||||
- [ ] Render with glBufferSubData
|
||||
- [x] Frustum Culling
|
||||
- [ ] Occlusion Culling
|
||||
|
||||
- [~] Occlusion Culling
|
||||
- Primitive raycast
|
||||
- [x] Document
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "../render/buffer/Abstract.hpp"
|
||||
#include "../data/geometry/Frustum.hpp"
|
||||
#include "../data/geometry/Faces.hpp"
|
||||
#include "../world/forward.h"
|
||||
#include "../data/geometry/Frustum.hpp"
|
||||
#include "../data/geometry/Ray.hpp"
|
||||
#include "../data/geometry/Faces.hpp"
|
||||
|
||||
/// Mesh creation
|
||||
namespace contouring {
|
||||
|
@ -32,6 +33,9 @@ namespace contouring {
|
|||
|
||||
/// Get buffers in frustum with model matrices
|
||||
/// @note buffers invalidated after update
|
||||
virtual void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &buffers, const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) = 0;
|
||||
virtual void getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) = 0;
|
||||
/// Get buffers hitting occlusion rays with model matrices
|
||||
/// @note buffers invalidated after update
|
||||
virtual void getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &draw, const glm::ifvec3 &from, float far, const std::vector<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) = 0;
|
||||
};
|
||||
}
|
|
@ -61,13 +61,36 @@ namespace contouring {
|
|||
ImGui::SliderInt("Keep Distance", &keepDistance, loadDistance+1, 21);
|
||||
}
|
||||
|
||||
void AbstractFlat::getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) {
|
||||
void AbstractFlat::getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &out, const std::optional<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) {
|
||||
const auto scaling = glm::scale(glm::mat4(1), glm::vec3(1.f / density));
|
||||
for (const auto [_, area] : buffers) {
|
||||
for (const auto [pos, buffer] : area.second) {
|
||||
const glm::vec3 fPos = (glm::vec3(area.first.raw_as_long() + glm::multiply(pos) - offset * glm::llvec3(density)) + area.first.offset) / glm::vec3(density);
|
||||
if (buffer != NULL && (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, glm::vec3(CHUNK_LENGTH / (float)density)))))
|
||||
out.emplace_back(glm::translate(scaling, fPos * (float)density), buffer);
|
||||
out(glm::translate(scaling, fPos * (float)density), buffer);
|
||||
}}
|
||||
}
|
||||
|
||||
void AbstractFlat::getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &out, const glm::ifvec3& from, float far, const std::vector<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) {
|
||||
const auto scaling = glm::scale(glm::mat4(1), glm::vec3(1.f / density));
|
||||
const auto start = glm::ifvec3(glm::divide(from.as_voxel(density)));
|
||||
const auto dist = far * density / CHUNK_LENGTH;
|
||||
for (const auto [_, area] : buffers) {
|
||||
const auto area_offset = glm::divide(area.first.as_voxel());
|
||||
robin_hood::unordered_set<chunk_pos> done;
|
||||
for (const auto& occ: occlusion) {
|
||||
const geometry::Ray ray(start, occ, dist);
|
||||
std::vector<voxel_pos> points; //TODO: iterator
|
||||
ray.grid(points);
|
||||
for(auto& point: points) {
|
||||
auto it = area.second.find(glm::lvec3(point) - area_offset);
|
||||
if(it != area.second.end() && it->second != NULL && done.insert(it->first).second) {
|
||||
const glm::vec3 fPos = glm::vec3(area.first.raw_as_long() + glm::multiply(it->first) - offset * glm::llvec3(density)) + area.first.offset;
|
||||
out(glm::translate(scaling, fPos), it->second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,10 @@ namespace contouring {
|
|||
|
||||
/// Get buffers in frustum with model matrices
|
||||
/// @note buffers invalidated after update
|
||||
void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) override;
|
||||
void getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density) override;
|
||||
/// Get buffers hitting occlusion rays with model matrices
|
||||
/// @note buffers invalidated after update
|
||||
void getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &draw, const glm::ifvec3 &from, float far, const std::vector<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) override;
|
||||
|
||||
protected:
|
||||
size_t clear(const voxel_pos &, const world::area_map &areas);
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace contouring {
|
|||
void onGui() override { }
|
||||
std::string getOptions() const override { return ""; }
|
||||
std::pair<float, float> getFarRange() const override { return std::make_pair(0, 0); }
|
||||
void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &, const std::optional<geometry::Frustum>&, const glm::llvec3&, int) override { }
|
||||
void getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &, const std::optional<geometry::Frustum> &, const glm::llvec3 &, int) override {}
|
||||
void getModels(const std::function<void(glm::mat4, buffer::Abstract *const)> &, const glm::ifvec3 &, float, const std::vector<glm::vec3> &, const glm::llvec3 &, int) override {}
|
||||
};
|
||||
}
|
|
@ -33,7 +33,7 @@ namespace contouring {
|
|||
loadedLevels.push_back(LEVELS[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 1; i <= 2; i++) {
|
||||
for (size_t i = 1; i <= std::thread::hardware_concurrency() / 2 - 1; i++) {
|
||||
workers.emplace_back([&] {
|
||||
#if TRACY_ENABLE
|
||||
tracy::SetThreadName("Contouring");
|
||||
|
@ -113,7 +113,7 @@ namespace contouring {
|
|||
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
|
||||
TracyPlot("CtLoaded", static_cast<int64_t>(loadedQueue.size()));
|
||||
for(auto handle = loadedQueue.extractor(); handle.first(out);) {
|
||||
const auto buffer = new buffer::LodShortIndexed(GL_TRIANGLES, out.second);
|
||||
const auto buffer = out.second.first.empty() ? NULL : new buffer::LodShortIndexed(GL_TRIANGLES, out.second);
|
||||
auto &bfs = buffers[out.first.first].second; //NOTE: buffer.first uninitialized (will be set in clear())
|
||||
if (const auto it = bfs.find(out.first.second); it != bfs.end()) {
|
||||
if(it->second != NULL)
|
||||
|
@ -143,8 +143,10 @@ namespace contouring {
|
|||
|
||||
it = bfs.erase(it);
|
||||
} else {
|
||||
static_cast<buffer::LodShortIndexed*>(it->second)->setLevel((1+lod_quality-distRatio)*levelMax*(1+lod_strength));
|
||||
buffer_count++;
|
||||
if(it->second != NULL) {
|
||||
static_cast<buffer::LodShortIndexed*>(it->second)->setLevel((1+lod_quality-distRatio)*levelMax*(1+lod_strength));
|
||||
buffer_count++;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
@ -244,14 +246,4 @@ namespace contouring {
|
|||
}
|
||||
}
|
||||
|
||||
void FlatDualMC::getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) {
|
||||
const auto scaling = glm::scale(glm::mat4(1), glm::vec3(1.f / density));
|
||||
for (const auto [_, area] : buffers) {
|
||||
for (const auto [pos, buffer] : area.second) {
|
||||
const glm::vec3 fPos = (glm::vec3(area.first.raw_as_long() + glm::multiply(pos) - offset * glm::llvec3(density)) + area.first.offset) / glm::vec3(density);
|
||||
if (buffer != NULL && (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, glm::vec3(CHUNK_LENGTH / (float)density))))) {
|
||||
out.emplace_back(glm::translate(scaling, fPos * (float)density), buffer);
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,6 @@ namespace contouring {
|
|||
/// @note notify for chunks entering view while moving
|
||||
void onNotify(const area_<chunk_pos> &, const chunk_pos &, const world::ChunkContainer &) override;
|
||||
|
||||
/// Get buffers in frustum with model matrices
|
||||
/// @note buffers invalidated after update
|
||||
void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) override;
|
||||
|
||||
protected:
|
||||
safe_priority_queue_map<area_<chunk_pos>, surrounding::corners, int, area_hash> loadQueue;
|
||||
safe_queue<std::pair<area_<chunk_pos>, buffer::LodShortIndexed::LodData>> loadedQueue;
|
||||
|
|
|
@ -46,6 +46,7 @@ inline std::vector<size_t> simplify_lod(std::vector<I> &indices, const std::vect
|
|||
simplify_buffer(part, full, vertices, threshold, error);
|
||||
meshopt_optimizeVertexCache(part.data(), part.data(), part.size(), vertices.size());
|
||||
offsets.push_back((offsets.empty() ? 0 : offsets.back()) + part.size());
|
||||
indices.reserve(indices.size() + part.size());
|
||||
indices.insert(indices.end(), part.begin(), part.end());
|
||||
}
|
||||
indices.reserve(indices.size() + full.size());
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
o = options;
|
||||
}
|
||||
|
||||
std::pair<float, float> getAngles() const { return std::make_pair(HorizontalAngle, VerticalAngle); }
|
||||
glm::vec3 getDirection() const { return glm::vec3(cos(VerticalAngle) * sin(HorizontalAngle), sin(VerticalAngle), cos(VerticalAngle) * cos(HorizontalAngle)); }
|
||||
struct axis {
|
||||
glm::vec3 direction;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
using namespace glm;
|
||||
ifvec3::ifvec3(const llvec3 &pos, uint density) {
|
||||
const auto d = IDX_LENGTH2 * density;
|
||||
raw = divide(pos, glm::uvec3(d));
|
||||
raw = glm::divide(pos, glm::uvec3(d));
|
||||
offset = glm::vec3(rem(pos.x, d), rem(pos.y, d), rem(pos.z, d));
|
||||
if(density > 1) center();
|
||||
}
|
||||
|
@ -15,10 +15,13 @@ llvec3 ifvec3::as_voxel(int density) const {
|
|||
return raw_as_long() * llvec3(density) + llvec3(offset * vec3(density));
|
||||
}
|
||||
void ifvec3::center() {
|
||||
const auto diff = divide(offset, uvec3(IDX_LENGTH2));
|
||||
const auto diff = glm::divide(glm::llvec3(offset), uvec3(IDX_LENGTH2));
|
||||
raw += diff;
|
||||
offset -= diff * static_cast<long>(IDX_LENGTH2);
|
||||
}
|
||||
double ifvec3::dist(const ifvec3& p) const {
|
||||
return glm::length(glm::dvec3(raw - p.raw)) + glm::length(offset - p.offset);
|
||||
}
|
||||
ifvec3 ifvec3::divide(uint m) const {
|
||||
return ifvec3(glm::divide(raw, glm::ucvec3(m)), glm::divide(offset, glm::uvec3(m)), false);
|
||||
}
|
|
@ -31,9 +31,10 @@ namespace glm {
|
|||
glm::llvec3 as_voxel(int density = 1) const;
|
||||
void center();
|
||||
glm::llvec3 raw_as_long() const;
|
||||
glm::dvec3 as_double() const;
|
||||
double dist(const ifvec3 &p) const;
|
||||
|
||||
ifvec3 divide(uint m = IDX_LENGTH) const;
|
||||
|
||||
inline const ifvec3 &operator+=(const offset_t &v) {
|
||||
offset += v;
|
||||
center();
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace glm {
|
|||
constexpr long inline div(long long value, uint m) {
|
||||
return value < 0 ? ((value+1) / (long long)m) - 1 : value / (long long)m;
|
||||
}
|
||||
constexpr float inline div(float value, uint m) {
|
||||
return value < 0 ? ((value+1) / m) - 1 : value / m;
|
||||
}
|
||||
constexpr ucvec3 inline modulo(const llvec3& value, const ucvec3& m = ucvec3(IDX_LENGTH)) {
|
||||
return ucvec3(rem(value.x, m.x), rem(value.y, m.y), rem(value.z, m.z));
|
||||
}
|
||||
|
@ -32,6 +35,9 @@ namespace glm {
|
|||
constexpr lvec3 inline divide(const llvec3 &value, const ucvec3 &m = ucvec3(IDX_LENGTH)) {
|
||||
return lvec3(div(value.x, m.x), div(value.y, m.y), div(value.z, m.z));
|
||||
}
|
||||
constexpr vec3 inline divide(const vec3 &value, const uvec3 &m) {
|
||||
return vec3(div(value.x, m.x), div(value.y, m.y), div(value.z, m.z));
|
||||
}
|
||||
constexpr llvec3 inline multiply(const lvec3 &value, const ucvec3 &m = ucvec3(IDX_LENGTH)) {
|
||||
return llvec3(value) * llvec3(m);
|
||||
}
|
||||
|
|
32
src/main.cpp
32
src/main.cpp
|
@ -195,29 +195,43 @@ int main(int /*unused*/, char */*unused*/[]){
|
|||
reports.models_count = 0;
|
||||
reports.tris_count = 0;
|
||||
std::optional<geometry::Frustum> frustum;
|
||||
if(options.culling) {
|
||||
if(options.culling >= 0) {
|
||||
frustum = {camera.getFrustum()};
|
||||
}
|
||||
const auto offset = state.position.raw_as_long();
|
||||
{ // Chunks
|
||||
std::vector<std::pair<glm::mat4, buffer::Abstract *const>> models;
|
||||
world.getContouring()->getModels(models, frustum, offset, options.voxel_density);
|
||||
for (auto [model, buffer] : models) {
|
||||
const auto draw = [&](glm::mat4 model, buffer::Abstract *const buffer) {
|
||||
reports.models_count++;
|
||||
reports.tris_count += buffer->draw(pass.setup(model));
|
||||
};
|
||||
if (options.culling > 0) {
|
||||
std::vector<glm::vec3> occlusion;
|
||||
const auto ratio = options.culling * 2;
|
||||
occlusion.reserve(glm::pow2(ratio * 2 - 1));
|
||||
const auto [ch, cv] = player.getAngles();
|
||||
const auto max_v = tan(options.camera.fov / 2.), max_h = RATIO * max_v;
|
||||
for(int iv = -ratio + 1; iv < ratio; iv++) {
|
||||
const auto v = cv + max_v * iv / ratio;
|
||||
for(int ih = -ratio + 1; ih < ratio; ih++) {
|
||||
const auto h = ch + max_h * ih / ratio;
|
||||
occlusion.emplace_back(cos(v) * sin(h), sin(v), cos(v) * cos(h));
|
||||
}
|
||||
}
|
||||
world.getContouring()->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density);
|
||||
} else {
|
||||
world.getContouring()->getModels(draw, frustum, offset, options.voxel_density);
|
||||
}
|
||||
}
|
||||
{ // Entities
|
||||
std::vector<std::pair<std::vector<glm::mat4>, buffer::Abstract *const>> models;
|
||||
world.getEntitiesModels(models, frustum, offset, options.voxel_density);
|
||||
lookProgram->useIt();
|
||||
lookProgram->start(renderer);
|
||||
for (auto [mats, buffer]: models) {
|
||||
for(auto model: mats) {
|
||||
const auto draw = [&](const std::vector<glm::mat4>& models, buffer::Abstract *const) {
|
||||
for(const auto& model: models) { //TODO: batch
|
||||
reports.models_count++;
|
||||
reports.tris_count += lookBuffer.draw(lookProgram->setup(renderer, model));
|
||||
}
|
||||
}
|
||||
};
|
||||
world.getEntitiesModels(draw, frustum, offset, options.voxel_density);
|
||||
}
|
||||
if(state.look_at.has_value()) { // Indicator
|
||||
lookProgram->useIt();
|
||||
|
|
|
@ -134,7 +134,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
actions |= Actions::ChangeContouring;
|
||||
contouring::save(options.contouring_idx, state.contouring, options.contouring_data);
|
||||
}
|
||||
ImGui::Checkbox("Culling", &options.culling);
|
||||
ImGui::SliderInt("Culling", &options.culling, -1, 10, options.culling > 0 ? "Occlusion %d" : (options.culling < 0 ? "None" : "Frustum"));
|
||||
state.contouring->onGui();
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ struct options {
|
|||
world.folderPath = config["world"]["path"].value_or(world.folderPath);
|
||||
voxel_density = config["world"]["voxel_density"].value_or(1);
|
||||
|
||||
culling = config["mesh"]["culling"].value_or(true);
|
||||
culling = config["mesh"]["culling"].value_or(culling);
|
||||
contouring_idx = contouring::idxByName(config["mesh"]["mode"].value_or(std::string("")));
|
||||
for(const auto& name: contouring::names) {
|
||||
contouring_data.emplace(name, config["mesh"]["options"][name].value_or(std::string("")));
|
||||
|
@ -163,7 +163,7 @@ struct options {
|
|||
int voxel_density;
|
||||
|
||||
bool show_debug_contouring;
|
||||
bool culling;
|
||||
int culling = 0;
|
||||
int contouring_idx;
|
||||
std::map<std::string, std::string> contouring_data;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ Universe::Universe(const Universe::options &options): dicts("content/zstd.dict"
|
|||
entities.emplace(nullptr, glm::vec3(1), glm::vec3(2));
|
||||
|
||||
// Workers
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
for (size_t i = 0; i < std::thread::hardware_concurrency() / 2 - 1; i++) {
|
||||
workers.emplace_back([&] {
|
||||
#if TRACY_ENABLE
|
||||
tracy::SetThreadName("Chunks");
|
||||
|
@ -439,15 +439,17 @@ bool Universe::collide_point(const glm::ifvec3 &pos, const glm::vec3 &vel, int d
|
|||
entity_instance_id Universe::addEntity(entity_id type, const Entity::Instance &instance) {
|
||||
return std::make_pair(type, entities.at(type).instances.push(instance));
|
||||
}
|
||||
void Universe::getEntitiesModels(std::vector<std::pair<std::vector<glm::mat4>, buffer::Abstract *const>> &buffers, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density) {
|
||||
void Universe::getEntitiesModels(const std::function<void(const std::vector<glm::mat4>&, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density) {
|
||||
std::vector<glm::mat4> mats;
|
||||
entities.iter([&](entity_id, const Entity &entity) {
|
||||
std::vector<glm::mat4> mats;
|
||||
entity.instances.iter([&](entity_id, const Entity::Instance &inst) {
|
||||
const glm::vec3 fPos = (glm::vec3(inst.pos.raw_as_long() - offset * glm::llvec3(density)) + inst.pos.offset) / glm::vec3(density);
|
||||
if (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, entity.size)))
|
||||
mats.emplace_back(glm::scale(glm::translate(glm::mat4(1), fPos * (float)density), entity.scale));
|
||||
});
|
||||
if(!mats.empty())
|
||||
buffers.emplace_back(mats, entity.buffer);
|
||||
if(!mats.empty()) {
|
||||
draw(mats, entity.buffer);
|
||||
mats.resize(0);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -93,7 +93,7 @@ namespace world {
|
|||
};
|
||||
/// Instante entity
|
||||
entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);
|
||||
void getEntitiesModels(std::vector<std::pair<std::vector<glm::mat4>, buffer::Abstract *const>> &buffers, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density);
|
||||
void getEntitiesModels(const std::function<void(const std::vector<glm::mat4>&, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density);
|
||||
|
||||
/// Change contouring worker
|
||||
void setContouring(const std::shared_ptr<contouring::Abstract>& ct);
|
||||
|
|
Loading…
Reference in New Issue