From d65828f3d75454015fe9afda069786e91d36316c Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 1 Oct 2021 15:14:31 +0200 Subject: [PATCH] Fix blending issues by sorting transparent objects --- src/client/blockmesh.c | 42 +++++++++++++++++++++++++++++------------ src/client/client_map.c | 2 +- src/client/game.c | 6 +----- src/client/gui.c | 4 ++++ src/client/object.c | 14 ++++++++++---- src/client/object.h | 4 +++- src/client/scene.c | 33 ++++++++++++++++++++++++++++---- src/client/scene.h | 2 ++ src/client/sky.c | 2 ++ 9 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/client/blockmesh.c b/src/client/blockmesh.c index 38a5d83..d98a1e3 100644 --- a/src/client/blockmesh.c +++ b/src/client/blockmesh.c @@ -16,14 +16,23 @@ static s32 half_block_size = MAPBLOCK_SIZE / 2; static void make_vertices(Object *object, MapBlock *block, bool hide_edges) { - v3s32 node_bp = {block->pos.x * MAPBLOCK_SIZE, block->pos.y * MAPBLOCK_SIZE, block->pos.z * MAPBLOCK_SIZE}; + object->visible = false; + v3s32 node_bp = { + block->pos.x * MAPBLOCK_SIZE, + block->pos.y * MAPBLOCK_SIZE, + block->pos.z * MAPBLOCK_SIZE + }; ITERATE_MAPBLOCK { MapNode *node = &block->data[x][y][z]; ClientNodeDefintion *def = &client_node_definitions[node->type]; if (def->visibility != NV_NONE) { - v3f32 offset = {x - half_block_size - 0.5, y - half_block_size - 0.5, z - half_block_size - 0.5}; + v3f32 offset = { + x - half_block_size - 0.5, + y - half_block_size - 0.5, + z - half_block_size - 0.5 + }; for (int f = 0; f < 6; f++) { v3s8 npos = { @@ -32,18 +41,27 @@ static void make_vertices(Object *object, MapBlock *block, bool hide_edges) z + fdir[f].z, }; - Node neighbor; + bool direct_neighbor = npos.x >= 0 && npos.x < MAPBLOCK_SIZE + && npos.y >= 0 && npos.y < MAPBLOCK_SIZE + && npos.z >= 0 && npos.z < MAPBLOCK_SIZE; - if (npos.x >= 0 && npos.x < MAPBLOCK_SIZE && npos.y >= 0 && npos.y < MAPBLOCK_SIZE && npos.z >= 0 && npos.z < MAPBLOCK_SIZE) - neighbor = block->data[npos.x][npos.y][npos.z].type; - else if (hide_edges) { - MapNode nn = map_get_node(client_map.map, (v3s32) {npos.x + node_bp.x, npos.y + node_bp.y, npos.z + node_bp.z}); - neighbor = nn.type; - } else { - neighbor = NODE_AIR; - } + MapNode neighbor = direct_neighbor + ? block->data[npos.x][npos.y][npos.z] + : map_get_node(client_map.map, (v3s32) {npos.x + node_bp.x, npos.y + node_bp.y, npos.z + node_bp.z}); + + bool transparency_edge = def->visibility != NV_TRANSPARENT || neighbor.type != node->type; + + bool render_node = neighbor.type != NODE_UNLOADED + && client_node_definitions[neighbor.type].visibility != NV_SOLID + && transparency_edge; + + object->visible = object->visible || render_node; + + if (! hide_edges && ! direct_neighbor) + render_node = transparency_edge; - if (neighbor != NODE_UNLOADED && client_node_definitions[neighbor].visibility != NV_SOLID && (def->visibility != NV_TRANSPARENT || neighbor != node->type)) { + if (render_node) { + object->transparent = object->transparent || def->visibility == NV_TRANSPARENT; object_set_texture(object, def->tiles.textures[f]); for (int v = 0; v < 6; v++) { diff --git a/src/client/client_map.c b/src/client/client_map.c index 6524573..93bd575 100644 --- a/src/client/client_map.c +++ b/src/client/client_map.c @@ -5,7 +5,7 @@ #include "client/client_map.h" #include "client/client_player.h" #include "util.h" -#define MAX_BLOCK_REQUESTS 4 +#define MAX_BLOCK_REQUESTS 8 struct ClientMap client_map; Client *client; diff --git a/src/client/game.c b/src/client/game.c index 62c33dd..979b254 100644 --- a/src/client/game.c +++ b/src/client/game.c @@ -53,12 +53,8 @@ static void render(f64 dtime) glFrontFace(GL_CCW); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - scene_render(dtime); - - glDisable(GL_CULL_FACE); sky_render(); - - glDisable(GL_DEPTH_TEST); + scene_render(dtime); gui_render(); } diff --git a/src/client/gui.c b/src/client/gui.c index 86f8547..bb90cae 100644 --- a/src/client/gui.c +++ b/src/client/gui.c @@ -273,7 +273,11 @@ static void render_element(BintreeNode *node, unused void *arg) void gui_render() { + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); bintree_traverse(&gui_root.children, BTT_INORDER, &render_element, NULL); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); } GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def) diff --git a/src/client/object.c b/src/client/object.c index 5c39d26..009ca1b 100644 --- a/src/client/object.c +++ b/src/client/object.c @@ -57,8 +57,9 @@ Object *object_create() obj->meshes_count = 0; obj->visible = true; obj->wireframe = false; - obj->box = (aabb3f32) {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}; obj->frustum_culling = false; + obj->transparent = false; + obj->box = (aabb3f32) {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}; obj->current_face = NULL; obj->faces = array_create(sizeof(ObjectFace)); obj->on_render = NULL; @@ -182,21 +183,26 @@ void object_transform(Object *obj) #pragma GCC diagnostic pop } -void object_render(Object *obj, f64 dtime) +bool object_before_render(Object *obj, f64 dtime) { if (obj->on_render) obj->on_render(obj, dtime); if (! obj->visible) - return; + return false; if (obj->frustum_culling) { aabb3f32 box = {v3f32_add(obj->box.min, obj->pos), v3f32_add(obj->box.max, obj->pos), }; if (! frustum_is_visible(box)) - return; + return false; } + return true; +} + +void object_render(Object *obj) +{ glUniformMatrix4fv(scene.loc_model, 1, GL_FALSE, obj->transform[0]); if (obj->wireframe) diff --git a/src/client/object.h b/src/client/object.h index 8c2fcdc..13fb1d9 100644 --- a/src/client/object.h +++ b/src/client/object.h @@ -56,6 +56,7 @@ typedef struct Object bool visible; bool wireframe; bool frustum_culling; + bool transparent; aabb3f32 box; ObjectFace *current_face; Array faces; @@ -69,6 +70,7 @@ void object_set_texture(Object *obj, Texture *texture); void object_add_vertex(Object *obj, Vertex3D *vertex); bool object_add_to_scene(Object *obj); void object_transform(Object *obj); -void object_render(Object *obj, f64 dtime); +bool object_before_render(Object *obj, f64 dtime); +void object_render(Object *obj); #endif diff --git a/src/client/scene.c b/src/client/scene.c index cbacfea..70109d0 100644 --- a/src/client/scene.c +++ b/src/client/scene.c @@ -10,9 +10,16 @@ struct Scene scene; +static int bintree_compare_f32(void *v1, void *v2, unused Bintree *tree) +{ + f32 diff = (*(f32 *) v2) - (*(f32 *) v1); + return CMPBOUNDS(diff); +} + bool scene_init() { - scene.objects = list_create(NULL), + scene.objects = list_create(NULL); + scene.render_objects = bintree_create(sizeof(f32), &bintree_compare_f32); pthread_mutex_init(&scene.mtx, NULL); glGetIntegerv(GL_MAX_TEXTURE_UNITS, &scene.max_texture_units); @@ -38,7 +45,7 @@ bool scene_init() glProgramUniform1iv(scene.prog, glGetUniformLocation(scene.prog, "textures"), scene.max_texture_units, texture_indices); scene.fov = 86.1f; - scene.render_distance = 255.0f + 32.0f; + scene.render_distance = 255.0f; return true; } @@ -62,16 +69,25 @@ void scene_add_object(Object *obj) pthread_mutex_unlock(&scene.mtx); } +static void bintree_render_object(BintreeNode *node, unused void *arg) +{ + object_render(node->value); +} + void scene_render(f64 dtime) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" mat4x4_mul(scene.VP, scene.projection, camera.view); +#pragma GCC diagnostic pop vec4 base_sunlight_dir = {0.0f, 0.0f, -1.0f, 1.0f}; vec4 sunlight_dir; mat4x4 sunlight_mat; mat4x4_identity(sunlight_mat); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" mat4x4_rotate(sunlight_mat, sunlight_mat, 1.0f, 0.0f, 0.0f, get_sun_angle() + M_PI / 2.0f); mat4x4_mul_vec4(sunlight_dir, sunlight_mat, base_sunlight_dir); #pragma GCC diagnostic pop @@ -94,15 +110,24 @@ void scene_render(f64 dtime) free(pair); object_delete(obj); } else { - object_render(obj, dtime); + f32 distance = sqrt(pow(obj->pos.x - camera.eye[0], 2) + pow(obj->pos.y - camera.eye[1], 2) + pow(obj->pos.z - camera.eye[2], 2)); + if (distance < scene.render_distance && object_before_render(obj, dtime)) { + if (obj->transparent) + bintree_insert(&scene.render_objects, &distance, obj); + else + object_render(obj); + } pairptr = &pair->next; } } + + bintree_traverse(&scene.render_objects, BTT_INORDER, &bintree_render_object, NULL); + bintree_clear(&scene.render_objects, NULL, NULL); } void scene_on_resize(int width, int height) { - mat4x4_perspective(scene.projection, scene.fov / 180.0f * M_PI, (float) width / (float) height, 0.01f, scene.render_distance); + mat4x4_perspective(scene.projection, scene.fov / 180.0f * M_PI, (float) width / (float) height, 0.01f, scene.render_distance + 28.0f); } GLuint scene_get_max_texture_units() diff --git a/src/client/scene.h b/src/client/scene.h index 29013de..1a27162 100644 --- a/src/client/scene.h +++ b/src/client/scene.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "client/object.h" @@ -11,6 +12,7 @@ extern struct Scene { List objects; + Bintree render_objects; pthread_mutex_t mtx; GLuint prog; GLint loc_model; diff --git a/src/client/sky.c b/src/client/sky.c index 5a4092f..5d9635e 100644 --- a/src/client/sky.c +++ b/src/client/sky.c @@ -228,6 +228,7 @@ void sky_render() mat4x4 MVP; mat4x4_mul(MVP, VP, model); + glDisable(GL_CULL_FACE); glDepthFunc(GL_LEQUAL); glUseProgram(sky.skybox_prog); @@ -245,5 +246,6 @@ void sky_render() mesh_render(sky.clouds_mesh); glDepthFunc(GL_LESS); + glEnable(GL_CULL_FACE); } #pragma GCC diagnostic pop -- 2.44.0