Voxel bitpacking
This commit is contained in:
parent
7d125b81d1
commit
f75afb5e1e
|
@ -117,7 +117,7 @@ namespace contouring {
|
|||
for (int x = 0; x < SIZE; x++) {
|
||||
const auto &chunk = surrounding[(z >= CHUNK_LENGTH) + (y >= CHUNK_LENGTH)*2 + (x >= CHUNK_LENGTH)*4];
|
||||
const auto &voxel = chunk->getAt(chunk_voxel_pos(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
|
||||
grid.emplace_back(voxel.Density * 1.f / UCHAR_MAX, voxel.Material);
|
||||
grid.emplace_back(voxel.density() * 1.f / world::Voxel::DENSITY_MAX, voxel.material());
|
||||
}}}
|
||||
}
|
||||
{
|
||||
|
|
|
@ -104,22 +104,22 @@ namespace contouring {
|
|||
}
|
||||
|
||||
bool FlatSurroundingBox::isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx) {
|
||||
return surrounding[idx.first]->get(idx.second).Density < UCHAR_MAX; // MAYBE: materials::transparent
|
||||
return surrounding[idx.first]->get(idx.second).density() < world::Voxel::DENSITY_MAX; // MAYBE: materials::transparent
|
||||
}
|
||||
|
||||
void FlatSurroundingBox::render(const surrounding::faces &surrounding, std::vector<buffer::VertexData> &vertices) {
|
||||
const auto center = surrounding[surrounding::CENTER];
|
||||
vertices.clear();
|
||||
for (ushort i = 0; i < CHUNK_SIZE; i++) {
|
||||
if (center->get(i).Density > 0) {
|
||||
Faces faces = center->get(i).Density < UCHAR_MAX ? Faces::All :
|
||||
if (center->get(i).density() > 0) {
|
||||
Faces faces = center->get(i).density() < world::Voxel::DENSITY_MAX ? Faces::All :
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Right)) & Faces::Right) |
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Left)) & Faces::Left) |
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Up)) & Faces::Up) |
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Down)) & Faces::Down) |
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Forward)) & Faces::Forward) |
|
||||
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Backward)) & Faces::Backward);
|
||||
box::addCube(vertices, world::Chunk::getPosition(i), center->get(i).Material, faces, glm::vec3(center->get(i).Density * 1.f / UCHAR_MAX));
|
||||
box::addCube(vertices, world::Chunk::getPosition(i), center->get(i).material(), faces, glm::vec3(center->get(i).density() * 1.f / world::Voxel::DENSITY_MAX));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "../render/window.hpp"
|
||||
|
||||
Camera::Camera(GLFWwindow *window, const InputMap& inputs, const Camera::options& opt): window(window), inputs(inputs),
|
||||
Position(voxel_pos(1ll << 24), 1), o(opt){
|
||||
Position(voxel_pos(0), 1), o(opt){
|
||||
updateProjection();
|
||||
}
|
||||
Camera::~Camera() { }
|
||||
|
|
|
@ -100,9 +100,9 @@ int main(int /*unused*/, char */*unused*/[]){
|
|||
state.look_at = world.raycast(camera.getRay() * options.voxel_density);
|
||||
if (state.capture_mouse && state.look_at.has_value()) {
|
||||
if (inputs.isPressing(Mouse::Left))
|
||||
world.setCube(state.look_at.value().first, world::Voxel{0, 0}, options.tool.radius);
|
||||
world.setCube(state.look_at.value().first, world::Voxel(0), options.tool.radius);
|
||||
else if (inputs.isPressing(Mouse::Right))
|
||||
world.setCube(state.look_at.value().first, world::Voxel{UCHAR_MAX, options.tool.material}, options.tool.radius);
|
||||
world.setCube(state.look_at.value().first, world::Voxel(options.tool.material, world::Voxel::DENSITY_MAX), options.tool.radius);
|
||||
}
|
||||
world.update((state.position * options.voxel_density).as_voxel(), reports.world);
|
||||
inputs.saveKeys();
|
||||
|
|
|
@ -166,7 +166,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
|
|||
if (options.editor_show) {
|
||||
ImGui::Begin("Editor", &options.editor_show, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
if (state.look_at.has_value()) {
|
||||
ImGui::Text("Look at: (%lld, %lld, %lld) (%s, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, world::materials::textures[state.look_at.value().second.Material].c_str(), state.look_at.value().second.Density * 1. / UCHAR_MAX);
|
||||
ImGui::Text("Look at: (%lld, %lld, %lld) (%s, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, world::materials::textures[state.look_at.value().second.material()].c_str(), state.look_at.value().second.density() * 1. / world::Voxel::DENSITY_MAX);
|
||||
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.x * 1. / options.voxel_density, state.look_at.value().first.y * 1. / options.voxel_density, state.look_at.value().first.z * 1. / options.voxel_density);
|
||||
} else {
|
||||
ImGui::Text("Look at: none");
|
||||
|
|
|
@ -7,71 +7,67 @@ using namespace world;
|
|||
|
||||
constexpr auto DENSITY = 0.f;
|
||||
constexpr auto GRANULARITY = 30.f;
|
||||
constexpr auto RLE = true;
|
||||
|
||||
Chunk::Chunk(const chunk_pos& pos, Generator& rnd) {
|
||||
const auto [densitySet, materialSet] = rnd.getChunk(pos, CHUNK_LENGTH);
|
||||
|
||||
for (size_t i = 0; i < CHUNK_SIZE; i++) {
|
||||
voxels[i].Density = std::clamp((densitySet[i] + DENSITY) * GRANULARITY, 0.f, 1.f) * UCHAR_MAX;
|
||||
voxels[i].Material = voxels[i].Density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet[i] + 1) / 2 * (materials::count - 2))),
|
||||
const auto density = std::clamp((densitySet[i] + DENSITY) * GRANULARITY, 0.f, 1.f) * Voxel::DENSITY_MAX;
|
||||
const auto material = density > 0 ? 1 + std::clamp(static_cast<int>(std::lrint((materialSet[i] + 1) / 2 * (materials::count - 2))),
|
||||
0, materials::count - 2) : 0; //NOTE: map (approx -1, 1) to (1, mat_max)
|
||||
voxels[i] = Voxel(material, density);
|
||||
}
|
||||
rnd.free(densitySet);
|
||||
rnd.free(materialSet);
|
||||
}
|
||||
Chunk::Chunk(std::istream& str) {
|
||||
if constexpr (RLE) {
|
||||
ushort i = 0;
|
||||
while(!str.eof()) {
|
||||
ushort count;
|
||||
Voxel voxel;
|
||||
str.read(reinterpret_cast<char *>(&count), sizeof(count));
|
||||
str.read(reinterpret_cast<char *>(&voxel.Density), sizeof(Voxel::Density));
|
||||
str.read(reinterpret_cast<char *>(&voxel.Material), sizeof(Voxel::Material));
|
||||
str.peek();
|
||||
for (; count > 0; count--) {
|
||||
voxels[i] = voxel;
|
||||
i++;
|
||||
Chunk::Chunk(std::istream& str, bool rle) {
|
||||
if(rle) {
|
||||
ushort i = 0;
|
||||
while(!str.eof()) {
|
||||
ushort count;
|
||||
Voxel voxel;
|
||||
str.read(reinterpret_cast<char *>(&count), sizeof(count));
|
||||
str.read(reinterpret_cast<char *>(&voxel), sizeof(voxel));
|
||||
str.peek();
|
||||
for (; count > 0; count--) {
|
||||
voxels[i] = voxel;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
assert(("Mismatch data length", i == CHUNK_SIZE-1));
|
||||
} else {
|
||||
for(auto& voxel: voxels) {
|
||||
str.read(reinterpret_cast<char *>(&voxel), sizeof(voxel));
|
||||
}
|
||||
}
|
||||
assert(("Mismatch data length", i == CHUNK_SIZE-1));
|
||||
} else {
|
||||
for(auto& voxel: voxels) {
|
||||
str.read(reinterpret_cast<char *>(&voxel.Density), sizeof(Voxel::Density));
|
||||
str.read(reinterpret_cast<char *>(&voxel.Material), sizeof(Voxel::Material));
|
||||
}
|
||||
}
|
||||
}
|
||||
Chunk::~Chunk() { }
|
||||
|
||||
void Chunk::write(std::ostream& str) const {
|
||||
if constexpr (RLE) {
|
||||
const auto *it = voxels.begin();
|
||||
ushort counter = 1;
|
||||
Voxel current = *it;
|
||||
while(true) {
|
||||
it++;
|
||||
const auto end = (it == voxels.end());
|
||||
if(end || current.Density != it->Density || current.Material != it->Material) {
|
||||
str.write(reinterpret_cast<char *>(&counter), sizeof(counter));
|
||||
str.write(reinterpret_cast<char *>(¤t.Density), sizeof(current.Density));
|
||||
str.write(reinterpret_cast<char *>(¤t.Material), sizeof(current.Material));
|
||||
if(end)
|
||||
break;
|
||||
void Chunk::write(std::ostream& str, bool rle) const {
|
||||
if (rle) {
|
||||
const auto *it = voxels.begin();
|
||||
ushort counter = 1;
|
||||
Voxel current = *it;
|
||||
while(true) {
|
||||
it++;
|
||||
const auto end = (it == voxels.end());
|
||||
if(end || current.value != it->value) {
|
||||
str.write(reinterpret_cast<char *>(&counter), sizeof(counter));
|
||||
str.write(reinterpret_cast<char *>(¤t), sizeof(current));
|
||||
if(end)
|
||||
break;
|
||||
|
||||
current = *it;
|
||||
counter = 1;
|
||||
} else {
|
||||
counter++;
|
||||
current = *it;
|
||||
counter = 1;
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(auto current: voxels) {
|
||||
str.write(reinterpret_cast<char *>(¤t), sizeof(current));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(auto current: voxels) {
|
||||
str.write(reinterpret_cast<char *>(¤t.Density), sizeof(current.Density));
|
||||
str.write(reinterpret_cast<char *>(¤t.Material), sizeof(current.Material));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Faces> Chunk::update() {
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
#define CHUNK_SIZE (CHUNK_LENGTH2 * CHUNK_LENGTH)
|
||||
|
||||
namespace world {
|
||||
constexpr auto RLE = true; //NOTE: only 2.7% gain after zstd
|
||||
using namespace geometry;
|
||||
/// World part as linear 3d voxel array
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk(const chunk_pos& pos, Generator& rnd);
|
||||
Chunk(std::istream& str);
|
||||
Chunk(std::istream& str, bool rle = RLE);
|
||||
~Chunk();
|
||||
|
||||
/// Update voxels
|
||||
|
@ -47,13 +48,12 @@ namespace world {
|
|||
const auto idx = getIdx(pos);
|
||||
const auto res = voxels[idx];
|
||||
set(idx, val);
|
||||
return Item{res.Density, res.Material};
|
||||
return Item{res.density(), res.material()};
|
||||
}
|
||||
// Is player modified
|
||||
inline bool isModified() const { return modified; }
|
||||
// Write to file.
|
||||
// Using RLE
|
||||
void write(std::ostream& str) const;
|
||||
void write(std::ostream& str, bool rle = RLE) const;
|
||||
|
||||
static inline chunk_voxel_pos getPosition(ushort idx) {
|
||||
return chunk_voxel_pos(idx / CHUNK_LENGTH2, (idx / CHUNK_LENGTH) % CHUNK_LENGTH, idx % CHUNK_LENGTH);
|
||||
|
|
|
@ -210,7 +210,7 @@ std::optional<std::pair<voxel_pos, Voxel>> Universe::raycast(const Ray &ray) con
|
|||
}
|
||||
if(chunk != NULL) {
|
||||
const auto voxel = chunk->getAt(glm::modulo(point, glm::uvec3(CHUNK_LENGTH)));
|
||||
if(voxel.Density > 0)
|
||||
if(voxel.density() > 0)
|
||||
return {{point, voxel}};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,35 @@
|
|||
namespace world {
|
||||
/// Universe unit
|
||||
struct Voxel {
|
||||
/// Packed value
|
||||
/// swap(1) + material(12) + density(3)
|
||||
uint16_t value;
|
||||
using material_t = uint_fast16_t;
|
||||
using density_t = uint_fast8_t;
|
||||
constexpr static const density_t DENSITY_MAX = 0b0111;
|
||||
|
||||
Voxel(uint16_t value = 0): value(value) { }
|
||||
Voxel(material_t material, density_t density, bool swap = false) {
|
||||
assert(density <= DENSITY_MAX);
|
||||
assert(material < (1 << 12));
|
||||
value = (swap & 0b1000'0000'0000'0000) |
|
||||
((material << 3) & 0b0111'1111'1111'1000) |
|
||||
(density & DENSITY_MAX);
|
||||
}
|
||||
|
||||
/// Quantity of material
|
||||
/// FIXME: low density area are cheatty
|
||||
/// @note v < iso * UCHAR_MAX are useless
|
||||
unsigned char Density;
|
||||
constexpr inline density_t density() const {
|
||||
return value & DENSITY_MAX;
|
||||
}
|
||||
/// Material type
|
||||
/// @see world::materials
|
||||
unsigned short Material;
|
||||
constexpr inline material_t material() const {
|
||||
return (value & 0b0111'1111'1111'1000) >> 3;
|
||||
}
|
||||
/// Swap value
|
||||
/// Use external metadata table
|
||||
constexpr inline bool swap() const {
|
||||
return value & 0b1000'0000'0000'0000;
|
||||
}
|
||||
};
|
||||
/// Stock of material
|
||||
struct Item {
|
||||
|
@ -19,7 +41,7 @@ namespace world {
|
|||
unsigned long long Count;
|
||||
/// Material type
|
||||
/// @see world::materials
|
||||
unsigned short Material;
|
||||
Voxel::material_t Material;
|
||||
};
|
||||
/// List of materials
|
||||
struct ItemList: std::map<unsigned short, unsigned long long> {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
namespace world::materials {
|
||||
/// Materials count
|
||||
static const auto count = 9;
|
||||
static_assert(count < (USHRT_MAX >> 4)); //NOTE: for byte packing see Voxel
|
||||
/// Materials textures
|
||||
static const std::array<std::string, count> textures = {{"Air", "Sand", "Dirt", "Stone_path", "Mapl", "Seaside_rock", "Stone_wall", "Rough_rock", "Alien"}};
|
||||
/// Materials roughness.
|
||||
|
|
Loading…
Reference in New Issue