Skip to content

Commit

Permalink
Merge pull request #548 from spazzylemons/culls_neighbors
Browse files Browse the repository at this point in the history
Add option to disable culling neighbors for VoxelBlockyModel
  • Loading branch information
Zylann authored Sep 24, 2023
2 parents 633e79a + 6492361 commit 75dfaf5
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 1 deletion.
3 changes: 3 additions & 0 deletions doc/classes/VoxelBlockyModel.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
Determines how transparency is handled when the sides of the model are culled by neighbor voxels.
Equal indices culls the face, different indexes doesn't.
</member>
<member name="culls_neighbors" type="bool" setter="set_culls_neighbors" getter="get_culls_neighbors" default="true">
If enabled, this voxel culls the faces of its neighbors. Disabling can be useful for denser transparent voxels, such as foliage.
</member>
<member name="transparent" type="bool" setter="set_transparent" getter="is_transparent" default="false">
Tells if the model is transparent in the context of sides being culled by neighbor voxels.
This is a legacy property, [member transparency_index] may be used instead.
Expand Down
5 changes: 5 additions & 0 deletions doc/source/api/VoxelBlockyModel.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Type | Name | Default
`Color` | [color](#i_color) | Color(1, 1, 1, 1)
`bool` | [random_tickable](#i_random_tickable) | false
`int` | [transparency_index](#i_transparency_index) | 0
`bool` | [culls_neighbors](#i_culls_neighbors) | true
`bool` | [transparent](#i_transparent) | false
<p></p>

Expand Down Expand Up @@ -72,6 +73,10 @@ Determines how transparency is handled when the sides of the model are culled by

Equal indices culls the face, different indexes doesn't.

- [bool](https://docs.godotengine.org/en/stable/classes/class_bool.html)<span id="i_culls_neighbors"></span> **culls_neighbors** = true

If enabled, this voxel culls the faces of its neighbors. Disabling can be useful for denser transparent voxels, such as foliage.

- [bool](https://docs.godotengine.org/en/stable/classes/class_bool.html)<span id="i_transparent"></span> **transparent** = false

Tells if the model is transparent in the context of sides being culled by neighbor voxels.
Expand Down
10 changes: 10 additions & 0 deletions doc/source/blocky_terrain.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ Here, glass has `transparency_index=2`, and leaves have `transparency_index=1`:

![Screenshot of transparency index being exploited](images/transparency_index_example2.webp)

`VoxelBlockyModel` also has a `culls_neighbors` property. This is enabled by default and prevents unnecessary rendering of neighboring voxel sides. However, for some transparent voxels it may be more desirable to always render neighboring voxel sides. For example, foliage can be made to look denser if all of the inner voxel sides
are visible.

Here is a group of leaves with `culls_neighbors=true` (the default):

![Screenshot of leaves with culls_neighbors set to true](images/culls_neighbors_enabled.webp)

Here is that same group of leaves with `culls_neighbors=false`. The sides in-between the voxels are rendered, making the group of leaves look less hollow.

![Screenshot of leaves with culls_neighbors set to false](images/culls_neighbors_disabled.webp)

### Random tick

Expand Down
Binary file added doc/source/images/culls_neighbors_disabled.webp
Binary file not shown.
Binary file added doc/source/images/culls_neighbors_enabled.webp
Binary file not shown.
11 changes: 11 additions & 0 deletions meshers/blocky/voxel_blocky_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ void VoxelBlockyModel::set_transparency_index(int i) {
_transparency_index = math::clamp(i, 0, 255);
}

void VoxelBlockyModel::set_culls_neighbors(bool cn) {
_culls_neighbors = cn;
}

void VoxelBlockyModel::set_surface_count(unsigned int new_count) {
if (new_count != _surface_count) {
_surface_count = new_count;
Expand All @@ -207,6 +211,7 @@ void VoxelBlockyModel::bake(BakedData &baked_data, bool bake_tangents, MaterialI

// baked_data.contributes_to_ao is set by the side culling phase
baked_data.transparency_index = _transparency_index;
baked_data.culls_neighbors = _culls_neighbors;
baked_data.color = _color;
baked_data.is_random_tickable = _random_tickable;
baked_data.box_collision_mask = _collision_mask;
Expand Down Expand Up @@ -308,6 +313,7 @@ void VoxelBlockyModel::copy_base_properties_from(const VoxelBlockyModel &src) {
_surface_params = src._surface_params;
// _surface_count = src._surface_count;
_transparency_index = src._transparency_index;
_culls_neighbors = src._culls_neighbors;
_random_tickable = src._random_tickable;
_color = src._color;
_collision_aabbs = src._collision_aabbs;
Expand Down Expand Up @@ -506,6 +512,10 @@ void VoxelBlockyModel::_bind_methods() {
D_METHOD("set_transparency_index", "transparency_index"), &VoxelBlockyModel::set_transparency_index);
ClassDB::bind_method(D_METHOD("get_transparency_index"), &VoxelBlockyModel::get_transparency_index);

ClassDB::bind_method(
D_METHOD("set_culls_neighbors", "culls_neighbors"), &VoxelBlockyModel::set_culls_neighbors);
ClassDB::bind_method(D_METHOD("get_culls_neighbors"), &VoxelBlockyModel::get_culls_neighbors);

ClassDB::bind_method(D_METHOD("is_random_tickable"), &VoxelBlockyModel::is_random_tickable);
ClassDB::bind_method(D_METHOD("set_random_tickable"), &VoxelBlockyModel::set_random_tickable);

Expand All @@ -529,6 +539,7 @@ void VoxelBlockyModel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE),
"set_transparent", "is_transparent");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency_index"), "set_transparency_index", "get_transparency_index");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "culls_neighbors"), "set_culls_neighbors", "get_culls_neighbors");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "random_tickable"), "set_random_tickable", "is_random_tickable");

ADD_GROUP("Box collision", "");
Expand Down
9 changes: 9 additions & 0 deletions meshers/blocky/voxel_blocky_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class VoxelBlockyModel : public Resource {
Model model;
Color color;
uint8_t transparency_index;
bool culls_neighbors;
bool contributes_to_ao;
bool empty;
bool is_random_tickable;
Expand Down Expand Up @@ -139,6 +140,11 @@ class VoxelBlockyModel : public Resource {
return _transparency_index;
}

void set_culls_neighbors(bool cn);
bool get_culls_neighbors() const {
return _culls_neighbors;
}

void set_collision_mask(uint32_t mask);
inline uint32_t get_collision_mask() const {
return _collision_mask;
Expand Down Expand Up @@ -241,6 +247,9 @@ class VoxelBlockyModel : public Resource {
// If two neighboring voxels are supposed to occlude their shared face,
// this index decides wether or not it should happen. Equal indexes culls the face, different indexes doesn't.
uint8_t _transparency_index = 0;
// If enabled, this voxel culls the faces of its neighbors. Disabling
// can be useful for denser transparent voxels, such as foliage.
bool _culls_neighbors = true;
bool _random_tickable = false;

Color _color;
Expand Down
2 changes: 1 addition & 1 deletion meshers/blocky/voxel_mesher_blocky.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ inline bool is_face_visible(const VoxelBlockyLibraryBase::BakedData &lib, const
uint32_t other_voxel_id, int side) {
if (other_voxel_id < lib.models.size()) {
const VoxelBlockyModel::BakedData &other_vt = lib.models[other_voxel_id];
if (other_vt.empty || (other_vt.transparency_index > vt.transparency_index)) {
if (other_vt.empty || (other_vt.transparency_index > vt.transparency_index) || !other_vt.culls_neighbors) {
return true;
} else {
const unsigned int ai = vt.model.side_pattern_indices[side];
Expand Down

0 comments on commit 75dfaf5

Please sign in to comment.