116 lines
4.1 KiB
C++
116 lines
4.1 KiB
C++
#ifndef VOXEL_DISTANCE_NORMALMAPS_H
|
|
#define VOXEL_DISTANCE_NORMALMAPS_H
|
|
|
|
#include "../util/fixed_array.h"
|
|
#include "../util/math/vector3f.h"
|
|
#include "../util/span.h"
|
|
|
|
#include <core/object/ref_counted.h>
|
|
#include <vector>
|
|
|
|
class Texture2DArray;
|
|
class Texture2D;
|
|
class Image;
|
|
|
|
namespace zylann::voxel {
|
|
|
|
class VoxelGenerator;
|
|
struct VoxelDataLodMap;
|
|
|
|
// TODO This system could be extended to more than just normals
|
|
// - Texturing data
|
|
// - Color
|
|
// - Some kind of depth (could be useful to fake water from far away)
|
|
|
|
// UV-mapping a voxel mesh is not trivial, but if mapping is required, an alternative is to subdivide the mesh into a
|
|
// grid of cells (we can use Transvoxel cells). In each cell, pick an axis-aligned projection working best with
|
|
// triangles of the cell using the average of their normals. A tile can then be generated by projecting its pixels on
|
|
// triangles, and be stored in an atlas. A shader can then read the atlas using a lookup texture to find the tile.
|
|
|
|
struct NormalMapSettings {
|
|
// If enabled, an atlas of normalmaps will be generated for each cell of the voxel mesh, in order to add
|
|
// more visual details using a shader.
|
|
bool enabled = false;
|
|
// LOD index from which normalmaps will start being generated.
|
|
uint8_t begin_lod_index = 2;
|
|
// Tile resolution that will be used starting from the beginning LOD. Resolution will double at each following
|
|
// LOD index.
|
|
uint8_t tile_resolution_min = 4;
|
|
uint8_t tile_resolution_max = 8;
|
|
// If enabled, encodes normalmaps using octahedral compression, which trades a bit of quality for
|
|
// significantly reduced memory usage (using 2 bytes per pixel instead of 3).
|
|
bool octahedral_encoding_enabled = false;
|
|
};
|
|
|
|
unsigned int get_virtual_texture_tile_resolution_for_lod(const NormalMapSettings &settings, unsigned int lod_index);
|
|
|
|
struct NormalMapData {
|
|
// Encoded normals
|
|
std::vector<uint8_t> normals;
|
|
struct Tile {
|
|
uint8_t x;
|
|
uint8_t y;
|
|
uint8_t z;
|
|
uint8_t axis;
|
|
};
|
|
std::vector<Tile> tiles;
|
|
|
|
inline void clear() {
|
|
normals.clear();
|
|
tiles.clear();
|
|
}
|
|
};
|
|
|
|
// To hold the current cell only. Not optimized for space. May use a more efficient structure per implementation of
|
|
// `ICellIterator`.
|
|
struct CurrentCellInfo {
|
|
static const unsigned int MAX_TRIANGLES = 5;
|
|
FixedArray<uint32_t, MAX_TRIANGLES> triangle_begin_indices;
|
|
uint32_t triangle_count = 0;
|
|
Vector3i position;
|
|
};
|
|
|
|
class ICellIterator {
|
|
public:
|
|
virtual ~ICellIterator() {}
|
|
virtual unsigned int get_count() const = 0;
|
|
virtual bool next(CurrentCellInfo &info) = 0;
|
|
};
|
|
|
|
// For each non-empty cell of the mesh, choose an axis-aligned projection based on triangle normals in the cell.
|
|
// Sample voxels inside the cell to compute a tile of world space normals from the SDF.
|
|
void compute_normalmap(ICellIterator &cell_iterator, Span<const Vector3f> mesh_vertices,
|
|
Span<const Vector3f> mesh_normals, Span<const int> mesh_indices, NormalMapData &normal_map_data,
|
|
unsigned int tile_resolution, VoxelGenerator &generator, const VoxelDataLodMap *voxel_data,
|
|
Vector3i origin_in_voxels, unsigned int lod_index, bool octahedral_encoding);
|
|
|
|
struct NormalMapImages {
|
|
Vector<Ref<Image>> atlas;
|
|
Ref<Image> lookup;
|
|
};
|
|
|
|
struct NormalMapTextures {
|
|
Ref<Texture2DArray> atlas;
|
|
Ref<Texture2D> lookup;
|
|
};
|
|
|
|
NormalMapImages store_normalmap_data_to_images(
|
|
const NormalMapData &data, unsigned int tile_resolution, Vector3i block_size, bool octahedral_encoding);
|
|
|
|
// Converts normalmap data into textures. They can be used in a shader to apply normals and obtain extra visual details.
|
|
// This may not be allowed to run in a different thread than the main thread if the renderer is not using Vulkan.
|
|
NormalMapTextures store_normalmap_data_to_textures(const NormalMapImages &data);
|
|
|
|
struct VirtualTextureOutput {
|
|
// Normalmap atlas used for smooth voxels.
|
|
// If textures can't be created from threads, images are returned instead.
|
|
NormalMapImages normalmap_images;
|
|
NormalMapTextures normalmap_textures;
|
|
// Can be false if textures are computed asynchronously. Will become true when it's done (and not change after).
|
|
std::atomic_bool valid;
|
|
};
|
|
|
|
} // namespace zylann::voxel
|
|
|
|
#endif // VOXEL_DISTANCE_NORMALMAPS_H
|