diff --git a/include/reign.h b/include/reign.h index 4c0e154..96360e8 100644 --- a/include/reign.h +++ b/include/reign.h @@ -186,6 +186,7 @@ struct RE_instance { mat4 local_transform; mat3 normal_transform; mat4 *bone_transforms; // model->nr_bones elements + GLuint bone_transforms_ubo; vec4 bounding_sphere; struct RE_instance *shadow_volume_instance; float z_from_camera; diff --git a/shaders/reign.v.glsl b/shaders/reign.v.glsl index 135805f..b16c089 100644 --- a/shaders/reign.v.glsl +++ b/shaders/reign.v.glsl @@ -30,10 +30,12 @@ uniform mat4 view_transform; uniform mat4 proj_transform; uniform mat3 normal_transform; -const int MAX_BONES = 211; // see 3d_internal.h +const int MAX_BONES = 308; // see 3d_internal.h const int NR_WEIGHTS = 4; uniform bool has_bones; -uniform mat4 bone_matrices[MAX_BONES]; +layout(std140) uniform BoneTransforms { + mat4 bone_matrices[MAX_BONES]; +}; uniform bool use_normal_map; diff --git a/shaders/reign_shadow.v.glsl b/shaders/reign_shadow.v.glsl index 41d07f9..6af53c5 100644 --- a/shaders/reign_shadow.v.glsl +++ b/shaders/reign_shadow.v.glsl @@ -17,10 +17,12 @@ uniform mat4 world_transform; uniform mat4 view_transform; -const int MAX_BONES = 211; // see 3d_internal.h +const int MAX_BONES = 308; // see 3d_internal.h const int NR_WEIGHTS = 4; uniform bool has_bones; -uniform mat4 bone_matrices[MAX_BONES]; +layout(std140) uniform BoneTransforms { + mat4 bone_matrices[MAX_BONES]; +}; in vec3 vertex_pos; in ivec4 vertex_bone_index; diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index b79e3c9..b0d2f05 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -26,7 +26,7 @@ #include "reign.h" #define NR_DIR_LIGHTS 3 -#define MAX_BONES 211 // Maximum in TT3 +#define MAX_BONES 308 // Maximum in Rance Quest typedef struct vec3_range { vec3 begin; @@ -111,7 +111,6 @@ struct shadow_renderer { GLint world_transform; GLint view_transform; GLint has_bones; - GLint bone_matrices; }; struct RE_renderer { @@ -128,7 +127,6 @@ struct RE_renderer { GLint normal_transform; GLint alpha_mod; GLint has_bones; - GLint bone_matrices; GLint ambient; struct { GLint dir; diff --git a/src/3d/reign.c b/src/3d/reign.c index 94fe5f8..929e189 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -75,6 +75,7 @@ static void unload_instance(struct RE_instance *instance) instance->effect = NULL; } if (instance->bone_transforms) { + glDeleteBuffers(1, &instance->bone_transforms_ubo); free(instance->bone_transforms); instance->bone_transforms = NULL; } @@ -182,6 +183,9 @@ static void update_bones(struct RE_instance *inst) glm_vec3_minv(aabb[0], bone_transform[3], aabb[0]); glm_vec3_maxv(aabb[1], bone_transform[3], aabb[1]); } + glBindBuffer(GL_UNIFORM_BUFFER, inst->bone_transforms_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, inst->model->nr_bones * sizeof(mat4), inst->bone_transforms); + glBindBuffer(GL_UNIFORM_BUFFER, 0); // Update inst->bounding_sphere. vec3 center; @@ -435,8 +439,13 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) if (instance->model) ht_put(instance->plugin->model_cache, name, instance->model); } - if (instance->model && instance->model->nr_bones > 0) + if (instance->model && instance->model->nr_bones > 0) { instance->bone_transforms = xcalloc(instance->model->nr_bones, sizeof(mat4)); + glGenBuffers(1, &instance->bone_transforms_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, instance->bone_transforms_ubo); + glBufferData(GL_UNIFORM_BUFFER, MAX_BONES * sizeof(mat4), NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } return !!instance->model; case RE_ITYPE_PARTICLE_EFFECT: pae = ht_get(instance->plugin->pae_cache, name, NULL); diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 4d28423..e80d42d 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -26,6 +26,8 @@ #include "reign.h" #include "sact.h" +#define BONE_TRANSFORMS_BINDING 0 + // TODO: Respect RE_plugin.shadow_map_resolution_level #define SHADOW_WIDTH 512 #define SHADOW_HEIGHT 512 @@ -100,7 +102,8 @@ static void init_shadow_renderer(struct shadow_renderer *sr) sr->world_transform = glGetUniformLocation(sr->program, "world_transform"); sr->view_transform = glGetUniformLocation(sr->program, "view_transform"); sr->has_bones = glGetUniformLocation(sr->program, "has_bones"); - sr->bone_matrices = glGetUniformLocation(sr->program, "bone_matrices"); + GLuint bone_transforms = glGetUniformBlockIndex(sr->program, "BoneTransforms"); + glUniformBlockBinding(sr->program, bone_transforms, BONE_TRANSFORMS_BINDING); glGenFramebuffers(1, &sr->fbo); glGenTextures(1, &sr->texture); @@ -181,7 +184,8 @@ struct RE_renderer *RE_renderer_new(void) r->normal_transform = glGetUniformLocation(r->program, "normal_transform"); r->alpha_mod = glGetUniformLocation(r->program, "alpha_mod"); r->has_bones = glGetUniformLocation(r->program, "has_bones"); - r->bone_matrices = glGetUniformLocation(r->program, "bone_matrices"); + GLuint bone_transforms = glGetUniformBlockIndex(r->program, "BoneTransforms"); + glUniformBlockBinding(r->program, bone_transforms, BONE_TRANSFORMS_BINDING); r->ambient = glGetUniformLocation(r->program, "ambient"); for (int i = 0; i < NR_DIR_LIGHTS; i++) { char buf[64]; @@ -423,7 +427,7 @@ static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r if (model->nr_bones > 0 && inst->motion) { glUniform1i(r->has_bones, GL_TRUE); - glUniformMatrix4fv(r->bone_matrices, model->nr_bones, GL_FALSE, inst->bone_transforms[0][0]); + glBindBufferBase(GL_UNIFORM_BUFFER, BONE_TRANSFORMS_BINDING, inst->bone_transforms_ubo); } else { glUniform1i(r->has_bones, GL_FALSE); } @@ -721,7 +725,7 @@ static void render_shadow_map(struct RE_plugin *plugin, mat4 light_space_transfo struct model *model = inst->model; if (model->nr_bones > 0) { glUniform1i(r->shadow.has_bones, GL_TRUE); - glUniformMatrix4fv(r->shadow.bone_matrices, model->nr_bones, GL_FALSE, inst->bone_transforms[0][0]); + glBindBufferBase(GL_UNIFORM_BUFFER, BONE_TRANSFORMS_BINDING, inst->bone_transforms_ubo); } else { glUniform1i(r->shadow.has_bones, GL_FALSE); } @@ -975,6 +979,14 @@ struct height_detector *RE_renderer_create_height_detector(struct RE_renderer *r glUniformMatrix4fv(r->shadow.view_transform, 1, GL_FALSE, proj_matrix[0]); glUniform1i(r->shadow.has_bones, GL_FALSE); + // Bone transforms are not used, but we still need to bind a UBO. + GLuint bone_transforms_ubo; + glGenBuffers(1, &bone_transforms_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, bone_transforms_ubo); + glBufferData(GL_UNIFORM_BUFFER, MAX_BONES * sizeof(mat4), NULL, GL_STATIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + glBindBufferBase(GL_UNIFORM_BUFFER, BONE_TRANSFORMS_BINDING, bone_transforms_ubo); + glEnable(GL_DEPTH_TEST); // Render the model. @@ -996,6 +1008,7 @@ struct height_detector *RE_renderer_create_height_detector(struct RE_renderer *r glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo); glViewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]); + glDeleteBuffers(1, &bone_transforms_ubo); glDeleteTextures(1, &color_texture); return hd; }