Commit e7d34b82 authored by Shu's avatar Shu 🍠
Browse files

Primitive occulision

parent c584a799
......@@ -91,6 +91,6 @@
- [x] Chunk size performance
- [ ] Render with glBufferSubData
- [x] Frustum Culling
- [ ] Occlusion Culling
- [~] Occlusion Culling
- Primitive raycast
- [x] Document
\ No newline at end of file
#pragma once
#include "../render/buffer/Abstract.hpp"
#include "../world/forward.h"
#include "../data/geometry/Frustum.hpp"
#include "../data/geometry/Ray.hpp"
#include "../data/geometry/Faces.hpp"
#include "../world/forward.h"
/// 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;
};
}
\ No newline at end of file
......@@ -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;
}
}
}
}
}
}
\ No newline at end of file
......@@ -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 {}
};
}
\ No newline at end of file
......@@ -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);
}
\ No newline at end of file
......@@ -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);
}
......
......@@ -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);
}
});
}
\ No newline at end of file
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment