From 31823f573106440c218c699711cd9dabe001ee1f Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 16 Oct 2022 22:01:31 +0900 Subject: [PATCH 1/6] ReignEngine: Draw instances in z-order To get correct blending effect for overlapped transparent objects. --- include/reign.h | 1 + src/3d/3d_internal.h | 3 +- src/3d/debug.c | 1 + src/3d/model.c | 6 ++++ src/3d/reign.c | 12 +++++-- src/3d/renderer.c | 86 +++++++++++++++++++++++++++++++------------- 6 files changed, 81 insertions(+), 28 deletions(-) diff --git a/include/reign.h b/include/reign.h index c4326ed..6111f5b 100644 --- a/include/reign.h +++ b/include/reign.h @@ -151,6 +151,7 @@ struct RE_instance { vec3 globe_diffuse; // Private + bool is_transparent; bool local_transform_needs_update; mat4 local_transform; mat3 normal_transform; diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index f4a07ab..d80a529 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -44,6 +44,7 @@ struct model { struct hash_table *bone_map; // bone id in POL/MOT -> struct bone * struct hash_table *bone_name_map; // bone name -> (struct bone * | NULL) vec3 aabb[2]; // axis-aligned bounding box + bool is_transparent; }; struct mesh { @@ -182,7 +183,7 @@ struct archive_data *RE_get_aar_entry(struct archive *aar, const char *dir, cons struct RE_renderer *RE_renderer_new(struct texture *texture); void RE_renderer_free(struct RE_renderer *r); -bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no); +struct billboard_texture *RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no); struct height_detector *RE_renderer_create_height_detector(struct RE_renderer *r, struct model *model); void RE_renderer_free_height_detector(struct height_detector *hd); float RE_renderer_detect_height(struct height_detector *hd, float x, float z); diff --git a/src/3d/debug.c b/src/3d/debug.c index 9473391..d12416c 100644 --- a/src/3d/debug.c +++ b/src/3d/debug.c @@ -98,6 +98,7 @@ static void print_instance(struct RE_instance *inst, int index, int indent) indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate); if (inst->effect) indent_printf(indent, "path = \"%s\",\n", inst->effect->path); + indent_printf(indent, "is_transparent = %d,\n", inst->is_transparent); indent--; indent_printf(indent, "},\n"); diff --git a/src/3d/model.c b/src/3d/model.c index 2bed90e..5cf7f1b 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -439,6 +439,12 @@ struct model *model_load(struct archive *aar, const char *path) &pol->materials[i].children[j], amt, aar, path); } } + for (int i = 0; i < model->nr_materials; i++) { + if (model->materials[i].alpha_map) { + model->is_transparent = true; + break; + } + } // Meshes for (uint32_t i = 0; i < pol->nr_meshes; i++) { diff --git a/src/3d/reign.c b/src/3d/reign.c index b3e5d8a..38f12dd 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -346,6 +346,7 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) instance->model = model_load(instance->plugin->aar, name); if (instance->model && instance->model->nr_bones > 0) instance->bone_transforms = xcalloc(instance->model->nr_bones, sizeof(mat4)); + instance->is_transparent = instance->model->is_transparent; return !!instance->model; case RE_ITYPE_PARTICLE_EFFECT: instance->effect = particle_effect_load(instance->plugin->aar, name); @@ -354,6 +355,7 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) instance->motion->instance = instance; particle_effect_calc_frame_range(instance->effect, instance->motion); } + instance->is_transparent = true; return !!instance->effect; default: WARNING("Invalid instance type %d", instance->type); @@ -496,8 +498,11 @@ bool RE_motion_set_frame_range(struct motion *motion, float begin, float end) motion->frame_end = end; if (motion->instance->type == RE_ITYPE_BILLBOARD) { for (int i = begin; i < end; i++) { - if (!RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i)) + struct billboard_texture *bt = RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i); + if (!bt) return false; + if (bt->has_alpha) + motion->instance->is_transparent = true; } } return true; @@ -511,8 +516,11 @@ bool RE_motion_set_loop_frame_range(struct motion *motion, float begin, float en motion->loop_frame_end = end; if (motion->instance->type == RE_ITYPE_BILLBOARD) { for (int i = begin; i < end; i++) { - if (!RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i)) + struct billboard_texture *bt = RE_renderer_load_billboard_texture(motion->instance->plugin->renderer, i); + if (!bt) return false; + if (bt->has_alpha) + motion->instance->is_transparent = true; } } return true; diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 5e157a7..143a0c3 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -14,6 +14,7 @@ * along with this program; if not, see . */ +#include #include #include "system4.h" @@ -214,16 +215,17 @@ struct RE_renderer *RE_renderer_new(struct texture *texture) return r; } -bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no) +struct billboard_texture *RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no) { - if (ht_get_int(r->billboard_textures, cg_no, NULL)) - return true; + struct billboard_texture *bt = ht_get_int(r->billboard_textures, cg_no, NULL); + if (bt) + return bt; struct cg *cg = asset_cg_load(cg_no); if (!cg) - return false; + return NULL; - struct billboard_texture *bt = xcalloc(1, sizeof(struct billboard_texture)); + bt = xcalloc(1, sizeof(struct billboard_texture)); glGenTextures(1, &bt->texture); glBindTexture(GL_TEXTURE_2D, bt->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels); @@ -237,7 +239,7 @@ bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no) cg_free(cg); ht_put_int(r->billboard_textures, cg_no, bt); - return true; + return bt; } static void free_billboard_texture(void *value) @@ -561,6 +563,26 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer glDepthMask(GL_TRUE); } +static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat) +{ + switch (inst->type) { + case RE_ITYPE_STATIC: + render_static_model(inst, r); + break; + case RE_ITYPE_SKINNED: + render_skinned_model(inst, r); + break; + case RE_ITYPE_BILLBOARD: + render_billboard(inst, r, view_mat); + break; + case RE_ITYPE_PARTICLE_EFFECT: + render_particle_effect(inst, r); + break; + default: + break; + } +} + static bool calc_shadow_light_transform(struct RE_plugin *plugin, mat4 dest) { // Compute AABB of shadow casters. @@ -704,6 +726,20 @@ static void setup_lights(struct RE_plugin *plugin) } } +static int cmp_instances_by_z(const void *lhs, const void *rhs) +{ + struct RE_instance *l = *(struct RE_instance **)lhs; + struct RE_instance *r = *(struct RE_instance **)rhs; + float lz = l ? l->pos[2] : FLT_MAX; + float rz = r ? r->pos[2] : FLT_MAX; + return (lz > rz) - (lz < rz); // ascending order. +} + +static bool is_transparent(struct RE_instance *inst) +{ + return inst->is_transparent || inst->alpha < 1.0f; +} + void RE_render(struct sact_sprite *sp) { struct RE_plugin *plugin = (struct RE_plugin *)sp->plugin; @@ -776,27 +812,27 @@ void RE_render(struct sact_sprite *sp) setup_lights(plugin); - for (int i = 0; i < plugin->nr_instances; i++) { - struct RE_instance *inst = plugin->instances[i]; - if (!inst) + // Sort instances by z-order. + struct RE_instance **sorted_instances = xmalloc(plugin->nr_instances * sizeof(struct RE_instance *)); + memcpy(sorted_instances, plugin->instances, plugin->nr_instances * sizeof(struct RE_instance *)); + qsort(sorted_instances, plugin->nr_instances, sizeof(struct RE_instance *), cmp_instances_by_z); + + // Render opaque instances, from nearest to farthest. + for (int i = plugin->nr_instances - 1; i >= 0; i--) { + struct RE_instance *inst = sorted_instances[i]; + if (!inst || is_transparent(inst)) continue; - switch (inst->type) { - case RE_ITYPE_STATIC: - render_static_model(inst, r); - break; - case RE_ITYPE_SKINNED: - render_skinned_model(inst, r); - break; - case RE_ITYPE_BILLBOARD: - render_billboard(inst, r, view_transform); - break; - case RE_ITYPE_PARTICLE_EFFECT: - render_particle_effect(inst, r); - break; - default: - break; - } + render_instance(inst, r, view_transform); } + // Render transparent instances, from nearest to farthest. + for (int i = 0; i < plugin->nr_instances; i++) { + struct RE_instance *inst = sorted_instances[i]; + if (!inst || !is_transparent(inst)) + continue; + render_instance(inst, r, view_transform); + } + + free(sorted_instances); plugin->proj_transform[1][1] *= -1; glFrontFace(GL_CCW); From 1a9a2e97533548de458ed32737833c040008a2ee Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 22 Oct 2022 21:29:48 +0900 Subject: [PATCH 2/6] ReignEngine: Support (nolighting) mesh attribute In ReignEngine, the mesh name field may contain keywords that change rendering behavior. The "(nolighting)" keyword disables lighting and fog. --- src/3d/3d_internal.h | 6 ++++++ src/3d/model.c | 1 + src/3d/parser.c | 9 +++++++++ src/3d/renderer.c | 16 +++++++++------- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index d80a529..f8eba7f 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -48,6 +48,7 @@ struct model { }; struct mesh { + uint32_t flags; GLuint vao; GLuint attr_buffer; int nr_vertices; @@ -380,8 +381,13 @@ struct pol_material_group { struct pol_material *children; }; +enum mesh_flags { + MESH_NOLIGHTING = 1 << 0, +}; + struct pol_mesh { char *name; + uint32_t flags; uint32_t material; uint32_t nr_vertices; struct pol_vertex *vertices; diff --git a/src/3d/model.c b/src/3d/model.c index 5cf7f1b..6cd4369 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -271,6 +271,7 @@ static void add_mesh(struct model *model, struct pol_mesh *m, int material_index } model->meshes = xrealloc_array(model->meshes, model->nr_meshes, model->nr_meshes + 1, sizeof(struct mesh)); struct mesh *mesh = &model->meshes[model->nr_meshes++]; + mesh->flags = m->flags; mesh->material = material; mesh->nr_vertices = nr_vertices; diff --git a/src/3d/parser.c b/src/3d/parser.c index c68ca4a..7345d05 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -148,6 +148,14 @@ static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle t->material = buffer_read_int32(r); } +static uint32_t parse_mesh_attributes(const char *name) +{ + uint32_t flags = 0; + if (strstr(name, "(nolighting)")) + flags |= MESH_NOLIGHTING; + return flags; +} + static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version) { int type = buffer_read_int32(r); @@ -158,6 +166,7 @@ static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version) } struct pol_mesh *mesh = xcalloc(1, sizeof(struct pol_mesh)); mesh->name = read_cstring(r); + mesh->flags = parse_mesh_attributes(mesh->name); mesh->material = buffer_read_int32(r); mesh->nr_vertices = buffer_read_int32(r); diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 143a0c3..5fddb1c 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -303,8 +303,11 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r) struct mesh *mesh = &model->meshes[i]; struct material *material = &model->materials[mesh->material]; + glUniform1i(r->fog_type, (inst->plugin->fog_mode && !(mesh->flags & MESH_NOLIGHTING)) + ? inst->plugin->fog_type : 0); + GLboolean use_specular_map = GL_FALSE; - if (inst->plugin->specular_mode) { + if (inst->plugin->specular_mode && !(mesh->flags & MESH_NOLIGHTING)) { glUniform1f(r->specular_strength, material->specular_strength); glUniform1f(r->specular_shininess, material->specular_shininess); if (material->specular_map) { @@ -326,7 +329,9 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r) glBindTexture(GL_TEXTURE_2D, material->color_map); glUniform1i(r->texture, COLOR_TEXTURE_UNIT); - if (material->light_map && inst->plugin->light_map_mode) { + if (mesh->flags & MESH_NOLIGHTING) { + glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE); + } else if (material->light_map && inst->plugin->light_map_mode) { glUniform1i(r->diffuse_type, DIFFUSE_LIGHT_MAP); glActiveTexture(GL_TEXTURE0 + LIGHT_TEXTURE_UNIT); glBindTexture(GL_TEXTURE_2D, material->light_map); @@ -422,6 +427,7 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma glUniform1i(r->use_normal_map, GL_FALSE); glUniform1i(r->use_shadow_map, GL_FALSE); glUniform1i(r->use_alpha_map, GL_FALSE); + glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, bt->texture); @@ -472,8 +478,6 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); - - glUniform1i(r->fog_type, inst->plugin->fog_type); } static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame) @@ -483,6 +487,7 @@ static void render_polygon_particles(struct RE_renderer *r, struct RE_instance * return; glUniform1i(r->diffuse_type, DIFFUSE_NORMAL); + glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0); for (int index = 0; index < po->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; @@ -789,7 +794,6 @@ void RE_render(struct sact_sprite *sp) glUniformMatrix4fv(r->shadow_transform, 1, GL_FALSE, shadow_transform[0]); glUniform1f(r->shadow_bias, plugin->shadow_bias); if (plugin->fog_mode) { - glUniform1i(r->fog_type, plugin->fog_type); switch (plugin->fog_type) { case RE_FOG_LINEAR: glUniform1f(r->fog_near, plugin->fog_near); @@ -803,8 +807,6 @@ void RE_render(struct sact_sprite *sp) glUniform3fv(r->ls_sun_color, 1, plugin->ls_sun_color); break; } - } else { - glUniform1i(r->fog_type, 0); } glEnable(GL_BLEND); From 814ebb7d3dad96408875a4789f6b6b0eb148a3d4 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 23 Oct 2022 10:05:23 +0900 Subject: [PATCH 3/6] ReignEngine: Support (sprite) material attribute If specified, alpha test is used instead of alpha blend. --- shaders/reign.f.glsl | 11 +++++++++-- src/3d/3d_internal.h | 8 +++++++- src/3d/model.c | 1 + src/3d/parser.c | 9 +++++++++ src/3d/renderer.c | 18 +++++++++++++----- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/shaders/reign.f.glsl b/shaders/reign.f.glsl index f4cb034..8d388f9 100644 --- a/shaders/reign.f.glsl +++ b/shaders/reign.f.glsl @@ -23,6 +23,10 @@ #define FOG_LINEAR 1 #define FOG_LIGHT_SCATTERING 2 +#define ALPHA_BLEND 0 +#define ALPHA_TEST 1 +#define ALPHA_MAP_BLEND 2 + struct dir_light { vec3 dir; vec3 diffuse; @@ -53,7 +57,7 @@ uniform int fog_type; uniform float fog_near; uniform float fog_far; uniform vec3 fog_color; -uniform bool use_alpha_map; +uniform int alpha_mode; in vec2 tex_coord; in vec2 light_tex_coord; @@ -139,7 +143,10 @@ void main() { // Alpha mapping float alpha = texel.a * alpha_mod; - if (use_alpha_map) { + if (alpha_mode == ALPHA_TEST) { + if (alpha < 1.0) + discard; + } else if (alpha_mode == ALPHA_MAP_BLEND) { alpha *= texture(alpha_texture, tex_coord).r; } diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index f8eba7f..927b657 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -56,6 +56,7 @@ struct mesh { }; struct material { + uint32_t flags; GLuint color_map; GLuint specular_map; GLuint alpha_map; @@ -153,7 +154,7 @@ struct RE_renderer { GLint ls_light_dir; GLint ls_light_color; GLint ls_sun_color; - GLint use_alpha_map; + GLint alpha_mode; GLint alpha_texture; GLuint billboard_vao; @@ -370,8 +371,13 @@ enum pol_texture_type { MAX_TEXTURE_TYPE }; +enum material_flags { + MATERIAL_SPRITE = 1 << 0, +}; + struct pol_material { char *name; + uint32_t flags; char *textures[MAX_TEXTURE_TYPE]; }; diff --git a/src/3d/model.c b/src/3d/model.c index 6cd4369..8f69c0c 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -89,6 +89,7 @@ static GLuint load_texture(struct archive *aar, const char *path, const char *na static bool init_material(struct material *material, const struct pol_material *m, struct amt *amt, struct archive *aar, const char *path) { + material->flags = m->flags; if (!m->textures[COLOR_MAP]) { WARNING("No color texture"); return false; diff --git a/src/3d/parser.c b/src/3d/parser.c index 7345d05..35e404b 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -59,9 +59,18 @@ static void read_quaternion(struct buffer *r, versor q) glm_quat_normalize(q); } +static uint32_t parse_material_attributes(const char *name) +{ + uint32_t flags = 0; + if (strstr(name, "(sprite)")) + flags |= MATERIAL_SPRITE; + return flags; +} + static void parse_material(struct buffer *r, struct pol_material *m) { m->name = read_cstring(r); + m->flags = parse_material_attributes(m->name); int nr_textures = buffer_read_int32(r); for (int i = 0; i < nr_textures; i++) { diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 5fddb1c..0bb0702 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -45,6 +45,12 @@ enum { DIFFUSE_LIGHT_MAP = 2, }; +enum { + ALPHA_BLEND = 0, + ALPHA_TEST = 1, + ALPHA_MAP_BLEND = 2, +}; + static GLuint load_shader(const char *vertex_shader_path, const char *fragment_shader_path) { GLuint program = glCreateProgram(); @@ -201,7 +207,7 @@ struct RE_renderer *RE_renderer_new(struct texture *texture) r->ls_light_dir = glGetUniformLocation(r->program, "ls_light_dir"); r->ls_light_color = glGetUniformLocation(r->program, "ls_light_color"); r->ls_sun_color = glGetUniformLocation(r->program, "ls_sun_color"); - r->use_alpha_map = glGetUniformLocation(r->program, "use_alpha_map"); + r->alpha_mode = glGetUniformLocation(r->program, "alpha_mode"); r->alpha_texture = glGetUniformLocation(r->program, "alpha_texture"); glGenRenderbuffers(1, &r->depth_buffer); @@ -350,12 +356,14 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r) } if (material->alpha_map) { - glUniform1i(r->use_alpha_map, GL_TRUE); + glUniform1i(r->alpha_mode, ALPHA_MAP_BLEND); glActiveTexture(GL_TEXTURE0 + ALPHA_TEXTURE_UNIT); glBindTexture(GL_TEXTURE_2D, material->alpha_map); glUniform1i(r->alpha_texture, ALPHA_TEXTURE_UNIT); + } else if (material->flags & MATERIAL_SPRITE) { + glUniform1i(r->alpha_mode, ALPHA_TEST); } else { - glUniform1i(r->use_alpha_map, GL_FALSE); + glUniform1i(r->alpha_mode, ALPHA_BLEND); } glBindVertexArray(mesh->vao); @@ -426,7 +434,7 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma glUniform1i(r->diffuse_type, DIFFUSE_NORMAL); glUniform1i(r->use_normal_map, GL_FALSE); glUniform1i(r->use_shadow_map, GL_FALSE); - glUniform1i(r->use_alpha_map, GL_FALSE); + glUniform1i(r->alpha_mode, ALPHA_BLEND); glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0); glActiveTexture(GL_TEXTURE0); @@ -536,7 +544,7 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer glUniform1f(r->rim_exponent, 0.0); glUniform1i(r->use_normal_map, GL_FALSE); glUniform1i(r->use_shadow_map, GL_FALSE); - glUniform1i(r->use_alpha_map, GL_FALSE); + glUniform1i(r->alpha_mode, ALPHA_BLEND); glDepthMask(GL_FALSE); From 241f631d9d7971aad609b7f9bfccdc45938ff50e Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 30 Oct 2022 11:13:56 +0900 Subject: [PATCH 4/6] ReignEngine: Set loop frame range for particle effects Without this, update_motion cannot calculate current_frame correctly when the effect is used with RE_MOTION_STATE_LOOP state. --- src/3d/particle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/3d/particle.c b/src/3d/particle.c index 9f39009..b9ac076 100644 --- a/src/3d/particle.c +++ b/src/3d/particle.c @@ -741,8 +741,8 @@ void particle_effect_calc_frame_range(struct particle_effect *effect, struct mot if (end_frame < obj_end) end_frame = obj_end; } - motion->frame_begin = begin_frame; - motion->frame_end = end_frame; + motion->frame_begin = motion->loop_frame_begin = begin_frame; + motion->frame_end = motion->loop_frame_end = end_frame; } static void update_camera_quake(struct RE_instance *inst, struct particle_object *po) From 581593f9b5b985fa8a326515b71eff8815e76807 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 5 Nov 2022 17:25:15 +0900 Subject: [PATCH 5/6] ReignEngine: Support (env) mesh attribute If specified, the mesh should be rendered with environment mapping using the material's COLOR_MAP as a matcap texture. --- shaders/reign.f.glsl | 30 +++++++++++++++++++----------- shaders/reign.v.glsl | 2 -- src/3d/3d_internal.h | 1 + src/3d/parser.c | 2 ++ src/3d/renderer.c | 5 ++++- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/shaders/reign.f.glsl b/shaders/reign.f.glsl index 8d388f9..6517383 100644 --- a/shaders/reign.f.glsl +++ b/shaders/reign.f.glsl @@ -19,6 +19,7 @@ #define DIFFUSE_EMISSIVE 0 #define DIFFUSE_NORMAL 1 #define DIFFUSE_LIGHT_MAP 2 +#define DIFFUSE_ENV_MAP 3 #define FOG_LINEAR 1 #define FOG_LIGHT_SCATTERING 2 @@ -85,19 +86,25 @@ void main() { vec3 frag_rgb = ambient; // Diffuse lighting - vec4 texel = texture(tex, tex_coord); - if (diffuse_type == DIFFUSE_EMISSIVE) { + vec4 texel; + if (diffuse_type == DIFFUSE_ENV_MAP) { + texel = texture(tex, (vec2(normal.x, -normal.y) + 1.0) / 2.0); frag_rgb = texel.rgb; } else { - vec3 diffuse = vec3(0.0); - for (int i = 0; i < NR_DIR_LIGHTS; i++) { - float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5; - diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert); + texel = texture(tex, tex_coord); + if (diffuse_type == DIFFUSE_EMISSIVE) { + frag_rgb = texel.rgb; + } else { + vec3 diffuse = vec3(0.0); + for (int i = 0; i < NR_DIR_LIGHTS; i++) { + float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5; + diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert); + } + if (diffuse_type == DIFFUSE_LIGHT_MAP) { + diffuse *= texture(light_texture, light_tex_coord).rgb; + } + frag_rgb += texel.rgb * diffuse; } - if (diffuse_type == DIFFUSE_LIGHT_MAP) { - diffuse *= texture(light_texture, light_tex_coord).rgb; - } - frag_rgb += texel.rgb * diffuse; } // Specular lighting @@ -113,7 +120,8 @@ void main() { // Rim lighting if (rim_exponent > 0.0) { // Normal map is not used here. - frag_rgb += pow(1.0 - max(dot(normalize(normal), view_dir), 0.0), rim_exponent) * rim_color; + vec3 n = use_normal_map ? vec3(0.0, 0.0, 1.0) : normalize(normal); + frag_rgb += pow(1.0 - max(dot(n, view_dir), 0.0), rim_exponent) * rim_color; } // Fog diff --git a/shaders/reign.v.glsl b/shaders/reign.v.glsl index f1e9d23..f126eb3 100644 --- a/shaders/reign.v.glsl +++ b/shaders/reign.v.glsl @@ -89,8 +89,6 @@ void main() { vec3 tangent = normal_bone_transform * vertex_tangent.xyz; vec3 bitangent = cross(normal, tangent) * vertex_tangent.w; TBN = transpose(mat3(tangent, bitangent, normal)); - // Tangent-space normal vector. - normal = vec3(0.0, 0.0, 1.0); } vec4 world_pos = local_bone_transform * vec4(vertex_pos, 1.0); diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 927b657..85380ca 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -389,6 +389,7 @@ struct pol_material_group { enum mesh_flags { MESH_NOLIGHTING = 1 << 0, + MESH_ENVMAP = 1 << 1, }; struct pol_mesh { diff --git a/src/3d/parser.c b/src/3d/parser.c index 35e404b..9e5eab0 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -162,6 +162,8 @@ static uint32_t parse_mesh_attributes(const char *name) uint32_t flags = 0; if (strstr(name, "(nolighting)")) flags |= MESH_NOLIGHTING; + if (strstr(name, "(env)")) + flags |= MESH_ENVMAP; return flags; } diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 0bb0702..9e68bfb 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -43,6 +43,7 @@ enum { DIFFUSE_EMISSIVE = 0, DIFFUSE_NORMAL = 1, DIFFUSE_LIGHT_MAP = 2, + DIFFUSE_ENV_MAP = 3, }; enum { @@ -335,7 +336,9 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r) glBindTexture(GL_TEXTURE_2D, material->color_map); glUniform1i(r->texture, COLOR_TEXTURE_UNIT); - if (mesh->flags & MESH_NOLIGHTING) { + if (mesh->flags & MESH_ENVMAP) { + glUniform1i(r->diffuse_type, DIFFUSE_ENV_MAP); + } else if (mesh->flags & MESH_NOLIGHTING) { glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE); } else if (material->light_map && inst->plugin->light_map_mode) { glUniform1i(r->diffuse_type, DIFFUSE_LIGHT_MAP); From 5f17dafdf823fa3683579cfa91c46566c1c6f82a Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 5 Nov 2022 22:17:38 +0900 Subject: [PATCH 6/6] ReignEngine: Set correct initial value for fog parameters This fixes rendering issue of the model viewer in Alice's Mansion. --- include/reign.h | 1 + src/3d/debug.c | 3 +++ src/3d/reign.c | 5 ++++- src/3d/renderer.c | 2 ++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/reign.h b/include/reign.h index 6111f5b..5e56be8 100644 --- a/include/reign.h +++ b/include/reign.h @@ -42,6 +42,7 @@ enum RE_motion_state { }; enum RE_fog_type { + RE_FOG_NONE = 0, RE_FOG_LINEAR = 1, RE_FOG_LIGHT_SCATTERING = 2, }; diff --git a/src/3d/debug.c b/src/3d/debug.c index d12416c..a669a2b 100644 --- a/src/3d/debug.c +++ b/src/3d/debug.c @@ -50,6 +50,7 @@ static const char *motion_state_name(enum RE_motion_state state) static const char *fog_type_name(enum RE_fog_type type) { switch (type) { + case RE_FOG_NONE: return "NONE"; case RE_FOG_LINEAR: return "LINEAR"; case RE_FOG_LIGHT_SCATTERING: return "LIGHT_SCATTERING"; } @@ -136,6 +137,8 @@ void RE_debug_print(struct sact_sprite *sp, int indent) indent_printf(indent, "fog_type = %s,\n", fog_type_name(p->fog_type)); switch (p->fog_type) { + case RE_FOG_NONE: + break; case RE_FOG_LINEAR: indent_printf(indent, "fog_near = %f, fog_far = %f,\n", p->fog_near, p->fog_far); indent_printf(indent, "fog_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->fog_color)); diff --git a/src/3d/reign.c b/src/3d/reign.c index 38f12dd..799d161 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -188,7 +188,10 @@ struct RE_plugin *RE_plugin_new(void) plugin->aar = aar; for (int i = 0; i < RE_NR_BACK_CGS; i++) RE_back_cg_init(&plugin->back_cg[i]); - plugin->fog_type = RE_FOG_LINEAR; + plugin->fog_type = RE_FOG_NONE; + plugin->fog_near = 1.0; + plugin->fog_far = 10.0; + glm_vec3_one(plugin->fog_color); return plugin; } diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 9e68bfb..7ffac7e 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -806,6 +806,8 @@ void RE_render(struct sact_sprite *sp) glUniform1f(r->shadow_bias, plugin->shadow_bias); if (plugin->fog_mode) { switch (plugin->fog_type) { + case RE_FOG_NONE: + break; case RE_FOG_LINEAR: glUniform1f(r->fog_near, plugin->fog_near); glUniform1f(r->fog_far, plugin->fog_far);