Ray out of range (loaded chunks)
This commit is contained in:
parent
bcd3475846
commit
c584a79908
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue