interface/mesh,atlas,voxel: Split geometry and physics generation into threadable and non-threadable parts
This commit is contained in:
parent
f13839a270
commit
8ae06bea14
@ -284,26 +284,22 @@ template<typename VoxelType>
|
||||
class IsQuadNeededByRegistry
|
||||
{
|
||||
interface::VoxelRegistry *m_voxel_reg;
|
||||
interface::TextureAtlasRegistry *m_atlas_reg;
|
||||
// NOTE: The voxel type id is used directly as PolyVox material value
|
||||
public:
|
||||
IsQuadNeededByRegistry(interface::VoxelRegistry *voxel_reg,
|
||||
interface::TextureAtlasRegistry *atlas_reg):
|
||||
m_voxel_reg(voxel_reg), m_atlas_reg(atlas_reg)
|
||||
IsQuadNeededByRegistry(interface::VoxelRegistry *voxel_reg):
|
||||
m_voxel_reg(voxel_reg)
|
||||
{}
|
||||
IsQuadNeededByRegistry(): // PolyVox wants this
|
||||
m_voxel_reg(nullptr),
|
||||
m_atlas_reg(nullptr)
|
||||
m_voxel_reg(nullptr)
|
||||
{}
|
||||
bool operator()(VoxelType backv, VoxelType front, uint32_t &materialToUse)
|
||||
bool operator()(VoxelType back, VoxelType front, uint32_t &materialToUse)
|
||||
{
|
||||
uint32_t back = backv.getId();
|
||||
if(m_voxel_reg == nullptr)
|
||||
throw Exception("IsQuadNeededByRegistry not initialized");
|
||||
const interface::CachedVoxelDefinition *back_def =
|
||||
m_voxel_reg->get_cached(back, m_atlas_reg);
|
||||
m_voxel_reg->get_cached(back);
|
||||
const interface::CachedVoxelDefinition *front_def =
|
||||
m_voxel_reg->get_cached(front, m_atlas_reg);
|
||||
m_voxel_reg->get_cached(front);
|
||||
if(!back_def){
|
||||
return false;
|
||||
}
|
||||
@ -311,39 +307,22 @@ public:
|
||||
return false;
|
||||
}
|
||||
else if(back_def->face_draw_type == interface::FaceDrawType::ALWAYS){
|
||||
materialToUse = back;
|
||||
materialToUse = back.getId();
|
||||
return true;
|
||||
}
|
||||
// interface::FaceDrawType::ON_EDGE
|
||||
if(!front_def){
|
||||
materialToUse = back;
|
||||
materialToUse = back.getId();
|
||||
return true;
|
||||
}
|
||||
if(back_def->edge_material_id != front_def->edge_material_id){
|
||||
materialToUse = back;
|
||||
materialToUse = back.getId();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
// TODO: Create a custom Drawable that can use an index buffer
|
||||
struct TemporaryGeometry
|
||||
{
|
||||
uint atlas_id = 0;
|
||||
sv_<float> vertex_data; // vertex(3) + normal(3) + texcoord(2)
|
||||
sv_<unsigned> index_data; // Urho3D eats unsigned as large indices
|
||||
};
|
||||
#else
|
||||
struct TemporaryGeometry
|
||||
{
|
||||
uint atlas_id = 0;
|
||||
// CustomGeometry can't handle an index buffer
|
||||
PODVector<CustomGeometryVertex> vertex_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
void assign_txcoords(size_t pv_vertex_i1, const AtlasSegmentCache *aseg,
|
||||
CustomGeometryVertex &tg_vert)
|
||||
{
|
||||
@ -422,13 +401,30 @@ void assign_txcoords(size_t pv_vertex_i1, const AtlasSegmentCache *aseg,
|
||||
}
|
||||
}
|
||||
|
||||
// Set custom geometry from voxel volume, using a voxel registry
|
||||
// Volume should be padded by one voxel on each edge
|
||||
void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
void preload_textures(pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg, TextureAtlasRegistry *atlas_reg)
|
||||
{
|
||||
auto region = volume.getEnclosingRegion();
|
||||
auto &lc = region.getLowerCorner();
|
||||
auto &uc = region.getUpperCorner();
|
||||
|
||||
for(int z = lc.getZ(); z <= uc.getZ(); z++){
|
||||
for(int y = lc.getY(); y <= uc.getY(); y++){
|
||||
for(int x = lc.getX(); x <= uc.getX(); x++){
|
||||
VoxelInstance v = volume.getVoxelAt(x, y, z);
|
||||
const interface::CachedVoxelDefinition *def =
|
||||
voxel_reg->get_cached(v, atlas_reg);
|
||||
(void)def; // Unused
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generate_voxel_geometry(sm_<uint, TemporaryGeometry> &result,
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg, TextureAtlasRegistry *atlas_reg)
|
||||
{
|
||||
IsQuadNeededByRegistry<VoxelInstance> iqn(voxel_reg, atlas_reg);
|
||||
IsQuadNeededByRegistry<VoxelInstance> iqn(voxel_reg);
|
||||
pv::SurfaceMesh<pv::PositionMaterialNormal> pv_mesh;
|
||||
pv::CubicSurfaceExtractorWithNormals<pv::RawVolume<VoxelInstance>,
|
||||
IsQuadNeededByRegistry<VoxelInstance>>
|
||||
@ -438,8 +434,6 @@ void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
const sv_<uint32_t> &pv_indices = pv_mesh.getIndices();
|
||||
const sv_<pv::PositionMaterialNormal> &pv_vertices = pv_mesh.getVertices();
|
||||
|
||||
sm_<uint, TemporaryGeometry> temp_geoms;
|
||||
|
||||
int w = volume.getWidth() - 2;
|
||||
int h = volume.getHeight() - 2;
|
||||
int d = volume.getDepth() - 2;
|
||||
@ -483,7 +477,7 @@ void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
#if 0
|
||||
// TODO: Create a custom Drawable that can use an index buffer
|
||||
// Get or create the appropriate temporary geometry for this atlas
|
||||
TemporaryGeometry &tg = temp_geoms[seg_ref.atlas_id];
|
||||
TemporaryGeometry &tg = result[seg_ref.atlas_id];
|
||||
if(tg.vertex_data.empty()){
|
||||
tg.atlas_id = seg_ref.atlas_id;
|
||||
// It can't get larger than these and will only exist temporarily in
|
||||
@ -527,7 +521,7 @@ void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
}
|
||||
#else
|
||||
// Get or create the appropriate temporary geometry for this atlas
|
||||
TemporaryGeometry &tg = temp_geoms[seg_ref.atlas_id];
|
||||
TemporaryGeometry &tg = result[seg_ref.atlas_id];
|
||||
if(tg.vertex_data.Empty()){
|
||||
tg.atlas_id = seg_ref.atlas_id;
|
||||
// It can't get larger than this and will only exist temporarily in
|
||||
@ -558,7 +552,12 @@ void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
const sm_<uint, TemporaryGeometry> &temp_geoms,
|
||||
TextureAtlasRegistry *atlas_reg)
|
||||
{
|
||||
// Generate CustomGeometry from TemporaryGeometry
|
||||
|
||||
ResourceCache *cache = context->GetSubsystem<ResourceCache>();
|
||||
@ -592,6 +591,20 @@ void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
cg->Commit();
|
||||
}
|
||||
|
||||
// Set custom geometry from voxel volume, using a voxel registry
|
||||
// Volume should be padded by one voxel on each edge
|
||||
void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg, TextureAtlasRegistry *atlas_reg)
|
||||
{
|
||||
preload_textures(volume, voxel_reg, atlas_reg);
|
||||
|
||||
sm_<uint, TemporaryGeometry> temp_geoms;
|
||||
generate_voxel_geometry(temp_geoms, volume, voxel_reg, atlas_reg);
|
||||
|
||||
set_voxel_geometry(cg, context, temp_geoms, atlas_reg);
|
||||
}
|
||||
|
||||
// Set custom geometry from voxel volume, using a voxel registry
|
||||
// Volume should be padded by one voxel on each edge
|
||||
void set_voxel_lod_geometry(int lod, CustomGeometry *cg, Context *context,
|
||||
@ -639,7 +652,9 @@ void set_voxel_lod_geometry(int lod, CustomGeometry *cg, Context *context,
|
||||
}
|
||||
}
|
||||
|
||||
IsQuadNeededByRegistry<VoxelInstance> iqn(voxel_reg, atlas_reg);
|
||||
preload_textures(volume, voxel_reg, atlas_reg);
|
||||
|
||||
IsQuadNeededByRegistry<VoxelInstance> iqn(voxel_reg);
|
||||
pv::SurfaceMesh<pv::PositionMaterialNormal> pv_mesh;
|
||||
pv::CubicSurfaceExtractorWithNormals<pv::RawVolume<VoxelInstance>,
|
||||
IsQuadNeededByRegistry<VoxelInstance>>
|
||||
@ -780,13 +795,8 @@ void set_voxel_lod_geometry(int lod, CustomGeometry *cg, Context *context,
|
||||
cg->Commit();
|
||||
}
|
||||
|
||||
struct TemporaryBox
|
||||
{
|
||||
Vector3 size;
|
||||
Vector3 position;
|
||||
};
|
||||
|
||||
void set_voxel_physics_boxes(Node *node, Context *context,
|
||||
void generate_voxel_physics_boxes(
|
||||
sv_<TemporaryBox> &result_boxes,
|
||||
pv::RawVolume<VoxelInstance> &volume_orig,
|
||||
VoxelRegistry *voxel_reg)
|
||||
{
|
||||
@ -816,8 +826,6 @@ void set_voxel_physics_boxes(Node *node, Context *context,
|
||||
// overlap. When a box is added, its voxels are set to value 2 in the
|
||||
// temporary volume.
|
||||
|
||||
sv_<TemporaryBox> result_boxes;
|
||||
|
||||
for(int z0 = lc.getZ(); z0 <= uc.getZ(); z0++){
|
||||
// Loop until this z0 plane is done, then handle the next one
|
||||
for(;;){
|
||||
@ -906,7 +914,11 @@ z_plane_does_not_fit:
|
||||
result_boxes.push_back(box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_voxel_physics_boxes(Node *node, Context *context,
|
||||
const sv_<TemporaryBox> &boxes)
|
||||
{
|
||||
// Get previous shapes
|
||||
PODVector<CollisionShape*> previous_shapes;
|
||||
node->GetComponents<CollisionShape>(previous_shapes);
|
||||
@ -921,7 +933,7 @@ z_plane_does_not_fit:
|
||||
body->ReleaseBody();
|
||||
|
||||
// Create the boxes (reuse previous shapes if possible)
|
||||
for(auto &box : result_boxes){
|
||||
for(auto &box : boxes){
|
||||
CollisionShape *shape = nullptr;
|
||||
if(num_shapes_reused < previous_shapes.Size())
|
||||
shape = previous_shapes[num_shapes_reused++];
|
||||
@ -943,6 +955,16 @@ z_plane_does_not_fit:
|
||||
}
|
||||
}
|
||||
|
||||
void set_voxel_physics_boxes(Node *node, Context *context,
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg)
|
||||
{
|
||||
sv_<TemporaryBox> result_boxes;
|
||||
generate_voxel_physics_boxes(result_boxes, volume, voxel_reg);
|
||||
|
||||
set_voxel_physics_boxes(node, context, result_boxes);
|
||||
}
|
||||
|
||||
} // namespace mesh
|
||||
} // namespace interface
|
||||
// vim: set noet ts=4 sw=4:
|
||||
|
@ -72,6 +72,7 @@ namespace interface
|
||||
{
|
||||
virtual ~TextureAtlasRegistry(){}
|
||||
|
||||
// These two may only be called from Urho3D main thread
|
||||
virtual const AtlasSegmentReference add_segment(
|
||||
const AtlasSegmentDefinition &segment_def) = 0;
|
||||
virtual const AtlasSegmentReference find_or_add_segment(
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include "core/types.h"
|
||||
#include "interface/voxel.h"
|
||||
#include <PolyVoxCore/RawVolume.h>
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#include <CustomGeometry.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
namespace Urho3D
|
||||
{
|
||||
@ -45,17 +49,66 @@ namespace interface
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg);
|
||||
|
||||
// Voxel geometry generation
|
||||
|
||||
#if 0
|
||||
// TODO: Create a custom Drawable that can use an index buffer
|
||||
struct TemporaryGeometry
|
||||
{
|
||||
uint atlas_id = 0;
|
||||
sv_<float> vertex_data; // vertex(3) + normal(3) + texcoord(2)
|
||||
sv_<unsigned> index_data; // Urho3D eats unsigned as large indices
|
||||
};
|
||||
#else
|
||||
struct TemporaryGeometry
|
||||
{
|
||||
uint atlas_id = 0;
|
||||
// CustomGeometry can't handle an index buffer
|
||||
PODVector<CustomGeometryVertex> vertex_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
void preload_textures(pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg, TextureAtlasRegistry *atlas_reg);
|
||||
|
||||
// Can be called from any thread
|
||||
void generate_voxel_geometry(sm_<uint, TemporaryGeometry> &result,
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg, TextureAtlasRegistry *atlas_reg);
|
||||
|
||||
void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
const sm_<uint, TemporaryGeometry> &temp_geoms,
|
||||
TextureAtlasRegistry *atlas_reg);
|
||||
|
||||
// Set custom geometry from voxel volume, using a voxel registry
|
||||
// Volume should be padded by one voxel on each edge
|
||||
// NOTE: volume is non-const due to PolyVox deficiency
|
||||
void set_voxel_geometry(CustomGeometry *cg, Context *context,
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg, TextureAtlasRegistry *atlas_reg);
|
||||
|
||||
// lod=1 -> 1:1, lod=3 -> 1:3
|
||||
void set_voxel_lod_geometry(int lod, CustomGeometry *cg, Context *context,
|
||||
pv::RawVolume<VoxelInstance> &volume_orig,
|
||||
VoxelRegistry *voxel_reg, TextureAtlasRegistry *atlas_reg);
|
||||
|
||||
// Voxel physics generation
|
||||
|
||||
struct TemporaryBox
|
||||
{
|
||||
Vector3 size;
|
||||
Vector3 position;
|
||||
};
|
||||
|
||||
// Can be called from any thread
|
||||
void generate_voxel_physics_boxes(
|
||||
sv_<TemporaryBox> &result_boxes,
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg);
|
||||
|
||||
void set_voxel_physics_boxes(Node *node, Context *context,
|
||||
const sv_<TemporaryBox> &boxes);
|
||||
|
||||
void set_voxel_physics_boxes(Node *node, Context *context,
|
||||
pv::RawVolume<VoxelInstance> &volume,
|
||||
VoxelRegistry *voxel_reg);
|
||||
|
@ -85,6 +85,8 @@ namespace interface
|
||||
|
||||
virtual const VoxelDefinition* get(const VoxelTypeId &id) = 0;
|
||||
virtual const VoxelDefinition* get(const VoxelName &name) = 0;
|
||||
|
||||
// atlas_reg may only be supplied when called from Urho3D main thread
|
||||
virtual const CachedVoxelDefinition* get_cached(const VoxelTypeId &id,
|
||||
TextureAtlasRegistry *atlas_reg = nullptr) = 0;
|
||||
virtual const CachedVoxelDefinition* get_cached(const VoxelInstance &v,
|
||||
|
Loading…
x
Reference in New Issue
Block a user