]> git.lizzy.rs Git - dragonblocks_alpha.git/commitdiff
Fix blending issues by sorting transparent objects
authorElias Fleckenstein <eliasfleckenstein@web.de>
Fri, 1 Oct 2021 13:14:31 +0000 (15:14 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Fri, 1 Oct 2021 13:14:31 +0000 (15:14 +0200)
src/client/blockmesh.c
src/client/client_map.c
src/client/game.c
src/client/gui.c
src/client/object.c
src/client/object.h
src/client/scene.c
src/client/scene.h
src/client/sky.c

index 38a5d8312f7b5f5e27edd1a84553253d0abe6628..d98a1e3b61be222be599cfd91846b9496566df85 100644 (file)
@@ -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++) {
index 6524573b4872b3f84e2a3db3622693c641114f3e..93bd5754e0dc408bf1aca71c3f89fc65577a65a7 100644 (file)
@@ -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;
index 62c33dd84e996ac6e33435cf0fb40c76620c5e8c..979b25420041d1c5912bc77eb6d5470d446997f8 100644 (file)
@@ -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();
 }
 
index 86f8547bd9dd3aacdb910e8463a618699a88ecb1..bb90caeeca9e53b5e9f276863a1ee723ae7fe8f2 100644 (file)
@@ -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)
index 5c39d267a943ec8d7809e63651dc9c89135d265d..009ca1bdf65344ab51f004f77a4135ab5581c653 100644 (file)
@@ -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)
index 8c2fcdc9d1699677491912b1f202bec5cf03b0d0..13fb1d9f7dc3fdc22b7a493067e7068493e43d7d 100644 (file)
@@ -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
index cbacfea737e1a5c5d28acf15ec9d8ed4e9bf88b7..70109d06b155ed99df473432c0524f6fe6fdeab1 100644 (file)
 
 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()
index 29013de592edf75902fd7238ab6183be05590c66..1a27162fd345fda502842417c636523afb8a3268 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdbool.h>
 #include <pthread.h>
 #include <linmath.h/linmath.h>
+#include <dragontype/bintree.h>
 #include <dragontype/list.h>
 #include <dragontype/number.h>
 #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;
index 5a4092f654a0eeb90f6278602798e663f6cc1492..5d9635e57382f1444e0cedbaa81ba4f736e1a14c 100644 (file)
@@ -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