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

Ray out of range (loaded chunks)

parent bcd34758
......@@ -193,7 +193,7 @@ namespace contouring {
auto &cell = grid[((z * SIZE) + y) * SIZE + x];
const auto &chunk = surrounding[(z >= CHUNK_LENGTH) + (y >= CHUNK_LENGTH)*2 + (x >= CHUNK_LENGTH)*4];
const auto &voxel = chunk->get(glm::toIdx(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
cell.x = voxel.density() * 1.f / world::Voxel::DENSITY_MAX;
cell.x = voxel.density_ratio();
cell.w = voxel.material();
}}}
}
......
......@@ -90,22 +90,22 @@ namespace contouring {
}
bool FlatSurroundingBox::isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx) {
return surrounding[idx.first]->get(idx.second).density() < world::Voxel::DENSITY_MAX; // MAYBE: materials::transparent
return !surrounding[idx.first]->get(idx.second).is_full(); // 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 < world::CHUNK_SIZE; i++) {
if (center->get(i).density() > 0) {
Faces faces = center->get(i).density() < world::Voxel::DENSITY_MAX ? Faces::All :
if (center->get(i).is_solid()) {
Faces faces = !center->get(i).is_full() ? 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, glm::fromIdx(i), center->get(i).material(), faces, glm::vec3(center->get(i).density() * 1.f / world::Voxel::DENSITY_MAX));
box::addCube(vertices, glm::fromIdx(i), center->get(i).material(), faces, glm::vec3(center->get(i).density_ratio()));
}
}
}
......
......@@ -120,7 +120,14 @@ int main(int /*unused*/, char */*unused*/[]){
camera.update();
renderer->lookFrom(camera);
state.look_at = world.raycast(camera.getRay() * options.voxel_density);
{
const auto ray_result = world.raycast(camera.getRay() * options.voxel_density);
if(auto target = std::get_if<world::Universe::ray_target>(&ray_result)) {
state.look_at = *target;
} else {
state.look_at = {};
}
}
if (state.capture_mouse) {
if (state.look_at.has_value()) {
if (inputs.isPressing(Mouse::Left))
......
......@@ -177,7 +177,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
if (state.look_at.has_value()) {
const auto &look = state.look_at.value();
ImGui::Text("Look at: (%ld: %lld, %lld, %lld) (%s, %.1f)", look.pos.first.index, look.pos.second.x, look.pos.second.y, look.pos.second.z,
world::materials::textures[look.value.material()].c_str(), look.value.density() * 1. / world::Voxel::DENSITY_MAX);
world::materials::textures[look.value.material()].c_str(), look.value.density_ratio());
const auto w_pos = look.pos.second + look.offset;
ImGui::Text("(%.3f, %.3f, %.3f)", w_pos.x * 1. / options.voxel_density, w_pos.y * 1. / options.voxel_density, w_pos.z * 1. / options.voxel_density);
} else {
......
......@@ -322,11 +322,11 @@ void Universe::setContouring(const std::shared_ptr<contouring::Abstract>& ct) {
last_pos = chunk_pos(INT_MAX); // trigger chunkChange on next update
}
std::optional<Universe::ray_target> Universe::raycast(const Ray &ray) const {
Universe::ray_result Universe::raycast(const Ray &ray) const {
//MAYBE: ray + offset to get float precision
std::vector<voxel_pos> points;
ray.grid(points);
std::optional<Universe::ray_target> target = std::nullopt;
ray_result target;
size_t dist = points.size();
for(auto& area: areas) {
if(ray.intersect(area.second->getBounding()) != IBox::ContainmentType::Disjoint) {
......@@ -341,16 +341,19 @@ std::optional<Universe::ray_target> Universe::raycast(const Ray &ray) const {
if (const auto it = chunks.find(cPos); it != chunks.end()) {
chunk = it->second;
chunk_vec = cPos;
} else if(chunks.inRange(cPos)) {
target.emplace<ray_out_of_range>(std::make_pair(area.first, cPos), offset);
break;
} else {
chunk = nullptr;
}
}
if(chunk != nullptr) {
const auto voxel = chunk->getAt(glm::modulo(pos));
if(voxel.density() > 0) {
target = {ray_target{{area.first, pos}, voxel, offset}};
if(voxel.is_solid()) {
target.emplace<ray_target>(std::make_pair(area.first, pos), voxel, offset);
dist = i;
i = points.size();
break;
}
}
}
......@@ -385,25 +388,53 @@ ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val, int ra
}
return list;
}
bool Universe::collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const {
const auto dir = glm::normalize(vel);
const auto velocity = vel * glm::vec3(density);
const auto from = pos * density + dir;
return raycast(Ray(from, dir, glm::length(velocity) + radius)).has_value();
}
bool Universe::move(glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const {
const auto dir = glm::normalize(vel);
const auto velocity = vel * glm::vec3(density);
const auto from = pos * density + dir;
if (const auto target = raycast(Ray(from, dir, glm::length(velocity) + radius))) {
const auto target_dist = from.dist(glm::ifvec3(target.value().offset + target.value().pos.second, density)) - radius;
const auto result = raycast(Ray(from, dir, glm::length(velocity) + radius));
if (auto target = std::get_if<ray_target>(&result)) {
const auto target_dist = from.dist(glm::ifvec3(target->offset + target->pos.second, density)) - radius;
pos += vel * glm::vec3(target_dist / glm::length(vel));
return true;
} else if(auto out = std::get_if<ray_out_of_range>(&result)) {
const auto out_dist = from.dist(glm::ifvec3(out->offset + glm::multiply(out->pos.second), density)) - radius - CHUNK_LENGTH;
pos += vel * glm::vec3(out_dist / glm::length(vel));
return true;
}
pos += vel;
return false;
}
bool Universe::collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const {
const auto dir = glm::normalize(vel);
const auto velocity = vel * glm::vec3(density);
const auto from = pos * density + dir;
return std::holds_alternative<ray_target>(raycast(Ray(from, dir, glm::length(velocity) + radius)));
}
bool Universe::collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const {
return std::holds_alternative<ray_target>(raycast(Ray((pos + vel) * density, vel, radius)));
}
bool Universe::collide_point(const glm::ifvec3 &pos, const glm::vec3 &vel, int density) const {
const auto target = ((pos + vel) * density).as_voxel();
for(auto& area: areas) {
if(area.second->getBounding().contains(target)) {
const auto &offset = area.second->getOffset().as_voxel();
const auto &chunks = area.second->getChunks();
const auto pos = target - offset;
const chunk_pos cPos = glm::divide(pos);
if (const auto it = chunks.find(cPos); it != chunks.end()) {
const auto voxel = it->second->getAt(glm::modulo(pos));
if (voxel.is_solid()) {
return true;
}
} else if(chunks.inRange(cPos)) {
return true;
}
}
}
return false;
}
entity_instance_id Universe::addEntity(entity_id type, const Entity::Instance &instance) {
return std::make_pair(type, entities.at(type).instances.push(instance));
......
......@@ -2,6 +2,7 @@
#include <string>
#include <thread>
#include <variant>
#include "../data/math.hpp"
#include "../data/safe_queue.hpp"
#include "../data/safe_priority_queue.hpp"
......@@ -44,23 +45,38 @@ namespace world {
void setOptions(const options &);
struct ray_target {
ray_target(area_<voxel_pos> pos, Voxel value, voxel_pos offset):
pos(pos), value(value), offset(offset) { }
area_<voxel_pos> pos;
Voxel value;
voxel_pos offset;
};
struct ray_out_of_range {
ray_out_of_range(area_<chunk_pos> pos, voxel_pos offset):
pos(pos), offset(offset) { }
area_<chunk_pos> pos;
voxel_pos offset;
};
/// @return target voxel, unloaded chunk or monostate
using ray_result = std::variant<std::monostate, ray_target, ray_out_of_range>;
/// Get nearest voxel colliding ray
/// @note ray in world scale
std::optional<ray_target> raycast(const geometry::Ray &ray) const;
ray_result raycast(const geometry::Ray &ray) const;
/// Set voxel at pos
std::optional<Item> set(const area_<voxel_pos> &pos, const Voxel &val);
/// Set cube of voxel with pos as center
/// MAYBE: allow set multi area
ItemList setCube(const area_<voxel_pos> &pos, const Voxel &val, int radius);
/// Check for collision on movement
bool collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius = 0) const;
/// Move with collision check
/// @note must remove velocity after colision
bool move(glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius = 0) const;
/// Check for collision on destination
bool collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const;
/// Check for collision at position
bool collide_point(const glm::ifvec3 &pos, const glm::vec3 &vel, int density) const;
/// Entities commun properties
struct Entity {
......
......@@ -25,6 +25,10 @@ namespace world {
constexpr inline density_t density() const {
return value & DENSITY_MAX;
}
/// Quantity of material on [0, 1]
constexpr inline float density_ratio() const {
return density() * 1.f / world::Voxel::DENSITY_MAX;
}
/// Material type
constexpr inline material_t material() const {
return (value & 0b0111'1111'1111'1000) >> 3;
......@@ -34,6 +38,14 @@ namespace world {
constexpr inline bool swap() const {
return value & 0b1000'0000'0000'0000;
}
/// Is solid
constexpr inline bool is_solid() const {
return density() > 0; //MAYBE: && materials::solid[material()]
}
/// Is full
constexpr inline bool is_full() const {
return density() == DENSITY_MAX;
}
};
/// Stock of material
struct Item {
......
Supports Markdown
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