Merge pull request #66 from kichikuou/shadow

ReignEngine: Implement shadow mapping
This commit is contained in:
Nunuhara Cabbage
2022-07-24 14:04:50 -07:00
committed by GitHub
12 changed files with 495 additions and 80 deletions
+1
View File
@@ -73,6 +73,7 @@ void gfx_update_screen_scale(void);
void gfx_set_wait_vsync(bool wait);
void gfx_load_shader(struct shader *dst, const char *vertex_shader_path, const char *fragment_shader_path);
GLuint gfx_load_shader_file(const char *path, GLenum type);
// rendering
void gfx_set_clear_color(int r, int g, int b, int a);
+6
View File
@@ -74,6 +74,9 @@ struct RE_plugin {
struct RE_back_cg back_cg[RE_NR_BACK_CGS];
vec3 shadow_map_light_dir;
float shadow_bias;
// Settings.
int render_mode;
int shadow_mode;
@@ -109,6 +112,9 @@ struct RE_instance {
vec3 scale;
float alpha;
bool draw;
bool draw_shadow;
bool make_shadow;
float shadow_volume_bone_radius;
bool draw_bump;
float fps;
bool motion_blend;
+21
View File
@@ -25,6 +25,7 @@ struct dir_light {
uniform sampler2D tex;
uniform sampler2D specular_texture;
uniform sampler2D light_texture;
uniform sampler2D shadow_texture;
uniform float alpha_mod;
uniform bool use_normal_map;
@@ -38,10 +39,13 @@ uniform bool use_specular_map;
uniform float rim_exponent;
uniform vec3 rim_color;
uniform bool use_light_map;
uniform bool use_shadow_map;
uniform float shadow_bias;
in vec2 tex_coord;
in vec2 light_tex_coord;
in vec3 frag_pos;
in vec4 shadow_frag_pos;
in vec3 eye;
in vec3 normal;
in vec3 light_dir[NR_DIR_LIGHTS];
@@ -88,5 +92,22 @@ void main() {
frag_rgb += pow(1.0 - max(dot(normalize(normal), view_dir), 0.0), rim_exponent) * rim_color;
}
// Shadow mapping
if (use_shadow_map) {
vec3 shadow_coords = shadow_frag_pos.xyz / shadow_frag_pos.w * 0.5 + 0.5;
shadow_coords.z = min(1.0, shadow_coords.z - shadow_bias);
// PCF with 9 samples.
float shadow_factor = 1.0;
vec2 texel_size = 1.0 / vec2(textureSize(shadow_texture, 0));
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
float depth = texture(shadow_texture, shadow_coords.xy + vec2(x, y) * texel_size).r;
if (depth < shadow_coords.z)
shadow_factor -= 0.05;
}
}
frag_rgb *= shadow_factor;
}
frag_color = vec4(frag_rgb, texel.a * alpha_mod);
}
+4
View File
@@ -37,6 +37,7 @@ uniform bool use_normal_map;
uniform vec3 view_pos;
uniform dir_light dir_lights[NR_DIR_LIGHTS];
uniform vec3 specular_light_dir;
uniform mat4 shadow_transform;
in vec3 vertex_pos;
in vec3 vertex_normal;
@@ -49,6 +50,7 @@ in vec4 vertex_bone_weight;
out vec2 tex_coord;
out vec2 light_tex_coord;
out vec3 frag_pos;
out vec4 shadow_frag_pos;
out vec3 eye;
out vec3 normal;
out vec3 light_dir[NR_DIR_LIGHTS];
@@ -86,6 +88,8 @@ void main() {
tex_coord = vertex_uv;
light_tex_coord = vertex_light_uv;
shadow_frag_pos = shadow_transform * world_pos;
// These are in tangent-space if use_normal_map is true, in world-space
// otherwise.
frag_pos = TBN * vec3(world_pos);
+18
View File
@@ -0,0 +1,18 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
void main() {
}
+42
View File
@@ -0,0 +1,42 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform mat4 world_transform;
uniform mat4 view_transform;
const int MAX_BONES = 211; // see 3d_internal.h
const int NR_WEIGHTS = 4;
uniform bool has_bones;
uniform mat4 bone_matrices[MAX_BONES];
in vec3 vertex_pos;
in ivec4 vertex_bone_index;
in vec4 vertex_bone_weight;
void main() {
mat4 world_bone_transform = world_transform;
if (has_bones) {
mat4 bone_transform = mat4(0.f);
for (int i = 0; i < NR_WEIGHTS; i++) {
if (vertex_bone_index[i] >= 0) {
bone_transform += bone_matrices[vertex_bone_index[i]] * vertex_bone_weight[i];
}
}
world_bone_transform *= bone_transform;
}
gl_Position = view_transform * world_bone_transform * vec4(vertex_pos, 1.0);
}
+31 -5
View File
@@ -36,6 +36,7 @@ struct model {
int nr_bones;
struct bone *bones;
struct hash_table *bone_map; // bone id in POL/MOT -> struct bone *
vec3 aabb[2]; // axis-aligned bounding box
};
struct mesh {
@@ -73,11 +74,33 @@ struct motion {
float loop_frame_begin, loop_frame_end;
};
struct RE_renderer {
struct shader shader;
GLuint depth_buffer;
enum RE_attribute_location {
ATTR_VERTEX_POS = 0,
ATTR_BONE_INDEX,
ATTR_BONE_WEIGHT,
};
struct shadow_renderer {
GLuint program;
GLuint fbo;
GLuint texture;
// Uniform variable locations
GLint world_transform;
GLint view_transform;
GLint has_bones;
GLint bone_matrices;
};
struct RE_renderer {
GLuint program;
GLuint depth_buffer;
struct shadow_renderer shadow;
// Uniform variable locations
GLint world_transform;
GLint view_transform;
GLint texture;
GLint local_transform;
GLint proj_transform;
GLint normal_transform;
@@ -103,14 +126,16 @@ struct RE_renderer {
GLint light_texture;
GLint use_normal_map;
GLint normal_texture;
GLint use_shadow_map;
GLint shadow_transform;
GLint shadow_texture;
GLint shadow_bias;
// Attribute variable locations
GLint vertex_normal;
GLint vertex_uv;
GLint vertex_light_uv;
GLint vertex_tangent;
GLint vertex_bone_index;
GLint vertex_bone_weight;
GLuint billboard_vao;
GLuint billboard_attr_buffer;
@@ -251,6 +276,7 @@ enum amt_field_index {
struct pol *pol_parse(uint8_t *data, size_t size);
void pol_free(struct pol *pol);
void pol_compute_aabb(struct pol *model, vec3 dest[2]);
struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id);
struct mot *mot_parse(uint8_t *data, size_t size);
+12 -10
View File
@@ -271,8 +271,8 @@ static void add_mesh(struct model *model, struct pol_mesh *m, int material_index
glBindBuffer(GL_ARRAY_BUFFER, mesh->attr_buffer);
const uint8_t *base = (const uint8_t *)0;
glEnableVertexAttribArray(r->shader.vertex);
glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, pos));
glEnableVertexAttribArray(ATTR_VERTEX_POS);
glVertexAttribPointer(ATTR_VERTEX_POS, 3, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, pos));
glEnableVertexAttribArray(r->vertex_normal);
glVertexAttribPointer(r->vertex_normal, 3, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, normal));
glEnableVertexAttribArray(r->vertex_uv);
@@ -295,16 +295,16 @@ static void add_mesh(struct model *model, struct pol_mesh *m, int material_index
glVertexAttrib3f(r->vertex_tangent, 1.0, 0.0, 0.0);
}
if (has_bones) {
glEnableVertexAttribArray(r->vertex_bone_index);
glVertexAttribIPointer(r->vertex_bone_index, NR_WEIGHTS, GL_INT, stride, base + offsetof(struct vertex_bones, bone_id));
glEnableVertexAttribArray(r->vertex_bone_weight);
glVertexAttribPointer(r->vertex_bone_weight, NR_WEIGHTS, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_bones, bone_weight));
glEnableVertexAttribArray(ATTR_BONE_INDEX);
glVertexAttribIPointer(ATTR_BONE_INDEX, NR_WEIGHTS, GL_INT, stride, base + offsetof(struct vertex_bones, bone_id));
glEnableVertexAttribArray(ATTR_BONE_WEIGHT);
glVertexAttribPointer(ATTR_BONE_WEIGHT, NR_WEIGHTS, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_bones, bone_weight));
base += sizeof(struct vertex_bones);
} else {
glDisableVertexAttribArray(r->vertex_bone_index);
glVertexAttribI4i(r->vertex_bone_index, 0, 0, 0, 0);
glDisableVertexAttribArray(r->vertex_bone_weight);
glVertexAttrib4f(r->vertex_bone_weight, 0.0, 0.0, 0.0, 0.0);
glDisableVertexAttribArray(ATTR_BONE_INDEX);
glVertexAttribI4i(ATTR_BONE_INDEX, 0, 0, 0, 0);
glDisableVertexAttribArray(ATTR_BONE_WEIGHT);
glVertexAttrib4f(ATTR_BONE_WEIGHT, 0.0, 0.0, 0.0, 0.0);
}
assert((intptr_t)base == stride);
@@ -440,6 +440,8 @@ struct model *model_load(struct archive *aar, const char *path, struct RE_render
}
}
pol_compute_aabb(pol, model->aabb);
free(material_offsets);
if (amt)
amt_free(amt);
+17
View File
@@ -295,6 +295,23 @@ void pol_free(struct pol *pol)
free(pol);
}
void pol_compute_aabb(struct pol *pol, vec3 dest[2])
{
vec3 aabb[2];
glm_aabb_invalidate(aabb);
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
struct pol_mesh *mesh = pol->meshes[i];
if (!mesh)
continue;
for (uint32_t j = 0; j < mesh->nr_vertices; j++) {
glm_vec3_minv(mesh->vertices[j].pos, aabb[0], aabb[0]);
glm_vec3_maxv(mesh->vertices[j].pos, aabb[1], aabb[1]);
}
}
glm_vec3_copy(aabb[0], dest[0]);
glm_vec3_copy(aabb[1], dest[1]);
}
struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id)
{
for (uint32_t i = 0; i < pol->nr_bones; i++) {
+238 -42
View File
@@ -25,13 +25,81 @@
#include "reign.h"
#include "sact.h"
// TODO: Respect RE_plugin.shadow_map_resolution_level
#define SHADOW_WIDTH 1024
#define SHADOW_HEIGHT 1024
enum {
COLOR_TEXTURE_UNIT,
SPECULAR_TEXTURE_UNIT,
LIGHT_TEXTURE_UNIT,
NORMAL_TEXTURE_UNIT,
SHADOW_TEXTURE_UNIT,
};
static GLuint load_shader(const char *vertex_shader_path, const char *fragment_shader_path)
{
GLuint program = glCreateProgram();
GLuint vertex_shader = gfx_load_shader_file(vertex_shader_path, GL_VERTEX_SHADER);
GLuint fragment_shader = gfx_load_shader_file(fragment_shader_path, GL_FRAGMENT_SHADER);
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
// Bind some attributes to fixed locations, so that common VAO can be used
// by multiple programs.
glBindAttribLocation(program, ATTR_VERTEX_POS, "vertex_pos");
glBindAttribLocation(program, ATTR_BONE_INDEX, "vertex_bone_index");
glBindAttribLocation(program, ATTR_BONE_WEIGHT, "vertex_bone_weight");
glLinkProgram(program);
GLint link_success;
glGetProgramiv(program, GL_LINK_STATUS, &link_success);
if (!link_success) {
GLint len;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
char *infolog = xmalloc(len + 1);
glGetProgramInfoLog(program, len, NULL, infolog);
ERROR("Failed to link shader %s, %s: %s", vertex_shader_path, fragment_shader_path, infolog);
}
return program;
}
static void init_shadow_renderer(struct shadow_renderer *sr)
{
GLint orig_fbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_fbo);
sr->program = load_shader("shaders/reign_shadow.v.glsl", "shaders/reign_shadow.f.glsl");
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");
glGenFramebuffers(1, &sr->fbo);
glGenTextures(1, &sr->texture);
glBindTexture(GL_TEXTURE_2D, sr->texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, sr->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, sr->texture, 0);
glDrawBuffers(0, NULL);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo);
}
static void destroy_shadow_renderer(struct shadow_renderer *sr)
{
glDeleteTextures(1, &sr->texture);
glDeleteFramebuffers(1, &sr->fbo);
glDeleteProgram(sr->program);
}
static void init_billboard_mesh(struct RE_renderer *r)
{
static const GLfloat vertices[] = {
@@ -46,8 +114,8 @@ static void init_billboard_mesh(struct RE_renderer *r)
glGenBuffers(1, &r->billboard_attr_buffer);
glBindBuffer(GL_ARRAY_BUFFER, r->billboard_attr_buffer);
glEnableVertexAttribArray(r->shader.vertex);
glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0);
glEnableVertexAttribArray(ATTR_VERTEX_POS);
glVertexAttribPointer(ATTR_VERTEX_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0);
glEnableVertexAttribArray(r->vertex_uv);
glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12);
glDisableVertexAttribArray(r->vertex_light_uv);
@@ -56,10 +124,10 @@ static void init_billboard_mesh(struct RE_renderer *r)
glVertexAttrib3f(r->vertex_normal, 0.0, 0.0, 1.0);
glDisableVertexAttribArray(r->vertex_tangent);
glVertexAttrib3f(r->vertex_tangent, 1.0, 0.0, 0.0);
glDisableVertexAttribArray(r->vertex_bone_index);
glVertexAttribI4i(r->vertex_bone_index, 0, 0, 0, 0);
glDisableVertexAttribArray(r->vertex_bone_weight);
glVertexAttrib4f(r->vertex_bone_weight, 0.0, 0.0, 0.0, 0.0);
glDisableVertexAttribArray(ATTR_BONE_INDEX);
glVertexAttribI4i(ATTR_BONE_INDEX, 0, 0, 0, 0);
glDisableVertexAttribArray(ATTR_BONE_WEIGHT);
glVertexAttrib4f(ATTR_BONE_WEIGHT, 0.0, 0.0, 0.0, 0.0);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
@@ -67,51 +135,63 @@ static void init_billboard_mesh(struct RE_renderer *r)
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
static void destroy_billboard_mesh(struct RE_renderer *r)
{
glDeleteVertexArrays(1, &r->billboard_vao);
glDeleteBuffers(1, &r->billboard_attr_buffer);
}
struct RE_renderer *RE_renderer_new(struct texture *texture)
{
struct RE_renderer *r = xcalloc(1, sizeof(struct RE_renderer));
gfx_load_shader(&r->shader, "shaders/reign.v.glsl", "shaders/reign.f.glsl");
r->local_transform = glGetUniformLocation(r->shader.program, "local_transform");
r->proj_transform = glGetUniformLocation(r->shader.program, "proj_transform");
r->normal_transform = glGetUniformLocation(r->shader.program, "normal_transform");
r->alpha_mod = glGetUniformLocation(r->shader.program, "alpha_mod");
r->has_bones = glGetUniformLocation(r->shader.program, "has_bones");
r->bone_matrices = glGetUniformLocation(r->shader.program, "bone_matrices");
r->ambient = glGetUniformLocation(r->shader.program, "ambient");
r->program = load_shader("shaders/reign.v.glsl", "shaders/reign.f.glsl");
r->world_transform = glGetUniformLocation(r->program, "world_transform");
r->view_transform = glGetUniformLocation(r->program, "view_transform");
r->texture = glGetUniformLocation(r->program, "tex");
r->local_transform = glGetUniformLocation(r->program, "local_transform");
r->proj_transform = glGetUniformLocation(r->program, "proj_transform");
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");
r->ambient = glGetUniformLocation(r->program, "ambient");
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
char buf[64];
sprintf(buf, "dir_lights[%d].dir", i);
r->dir_lights[i].dir = glGetUniformLocation(r->shader.program, buf);
r->dir_lights[i].dir = glGetUniformLocation(r->program, buf);
sprintf(buf, "dir_lights[%d].diffuse", i);
r->dir_lights[i].diffuse = glGetUniformLocation(r->shader.program, buf);
r->dir_lights[i].diffuse = glGetUniformLocation(r->program, buf);
sprintf(buf, "dir_lights[%d].globe_diffuse", i);
r->dir_lights[i].globe_diffuse = glGetUniformLocation(r->shader.program, buf);
r->dir_lights[i].globe_diffuse = glGetUniformLocation(r->program, buf);
}
r->specular_light_dir = glGetUniformLocation(r->shader.program, "specular_light_dir");
r->specular_strength = glGetUniformLocation(r->shader.program, "specular_strength");
r->specular_shininess = glGetUniformLocation(r->shader.program, "specular_shininess");
r->use_specular_map = glGetUniformLocation(r->shader.program, "use_specular_map");
r->specular_texture = glGetUniformLocation(r->shader.program, "specular_texture");
r->rim_exponent = glGetUniformLocation(r->shader.program, "rim_exponent");
r->rim_color = glGetUniformLocation(r->shader.program, "rim_color");
r->view_pos = glGetUniformLocation(r->shader.program, "view_pos");
r->use_light_map = glGetUniformLocation(r->shader.program, "use_light_map");
r->light_texture = glGetUniformLocation(r->shader.program, "light_texture");
r->use_normal_map = glGetUniformLocation(r->shader.program, "use_normal_map");
r->normal_texture = glGetUniformLocation(r->shader.program, "normal_texture");
r->vertex_normal = glGetAttribLocation(r->shader.program, "vertex_normal");
r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv");
r->vertex_light_uv = glGetAttribLocation(r->shader.program, "vertex_light_uv");
r->vertex_tangent = glGetAttribLocation(r->shader.program, "vertex_tangent");
r->vertex_bone_index = glGetAttribLocation(r->shader.program, "vertex_bone_index");
r->vertex_bone_weight = glGetAttribLocation(r->shader.program, "vertex_bone_weight");
r->specular_light_dir = glGetUniformLocation(r->program, "specular_light_dir");
r->specular_strength = glGetUniformLocation(r->program, "specular_strength");
r->specular_shininess = glGetUniformLocation(r->program, "specular_shininess");
r->use_specular_map = glGetUniformLocation(r->program, "use_specular_map");
r->specular_texture = glGetUniformLocation(r->program, "specular_texture");
r->rim_exponent = glGetUniformLocation(r->program, "rim_exponent");
r->rim_color = glGetUniformLocation(r->program, "rim_color");
r->view_pos = glGetUniformLocation(r->program, "view_pos");
r->use_light_map = glGetUniformLocation(r->program, "use_light_map");
r->light_texture = glGetUniformLocation(r->program, "light_texture");
r->use_normal_map = glGetUniformLocation(r->program, "use_normal_map");
r->normal_texture = glGetUniformLocation(r->program, "normal_texture");
r->use_shadow_map = glGetUniformLocation(r->program, "use_shadow_map");
r->shadow_transform = glGetUniformLocation(r->program, "shadow_transform");
r->shadow_texture = glGetUniformLocation(r->program, "shadow_texture");
r->shadow_bias = glGetUniformLocation(r->program, "shadow_bias");
r->vertex_normal = glGetAttribLocation(r->program, "vertex_normal");
r->vertex_uv = glGetAttribLocation(r->program, "vertex_uv");
r->vertex_light_uv = glGetAttribLocation(r->program, "vertex_light_uv");
r->vertex_tangent = glGetAttribLocation(r->program, "vertex_tangent");
glGenRenderbuffers(1, &r->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, r->depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, texture->w, texture->h);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
init_shadow_renderer(&r->shadow);
init_billboard_mesh(r);
r->billboard_textures = ht_create(256);
return r;
@@ -151,12 +231,12 @@ static void free_billboard_texture(void *value)
void RE_renderer_free(struct RE_renderer *r)
{
glDeleteProgram(r->shader.program);
glDeleteProgram(r->program);
glDeleteRenderbuffers(1, &r->depth_buffer);
ht_foreach_value(r->billboard_textures, free_billboard_texture);
ht_free_int(r->billboard_textures);
glDeleteVertexArrays(1, &r->billboard_vao);
glDeleteBuffers(1, &r->billboard_attr_buffer);
destroy_billboard_mesh(r);
destroy_shadow_renderer(&r->shadow);
free(r);
}
@@ -191,6 +271,15 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
glUniform3fv(r->ambient, 1, ambient);
if (inst->draw_shadow && inst->plugin->shadow_mode) {
glUniform1i(r->use_shadow_map, GL_TRUE);
glActiveTexture(GL_TEXTURE0 + SHADOW_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, r->shadow.texture);
glUniform1i(r->shadow_texture, SHADOW_TEXTURE_UNIT);
} else {
glUniform1i(r->use_shadow_map, GL_FALSE);
}
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
struct material *material = &model->materials[mesh->material];
@@ -216,7 +305,7 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
glActiveTexture(GL_TEXTURE0 + COLOR_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->color_map);
glUniform1i(r->shader.texture, COLOR_TEXTURE_UNIT);
glUniform1i(r->texture, COLOR_TEXTURE_UNIT);
if (material->light_map && inst->plugin->light_map_mode) {
glUniform1i(r->use_light_map, GL_TRUE);
@@ -298,7 +387,7 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bt->texture);
glUniform1i(r->shader.texture, 0);
glUniform1i(r->texture, 0);
glBindVertexArray(r->billboard_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -307,6 +396,105 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
glBindTexture(GL_TEXTURE_2D, 0);
}
static bool calc_shadow_light_transform(struct RE_plugin *plugin, mat4 dest)
{
// Compute AABB of shadow casters.
vec3 aabb[2];
glm_aabb_invalidate(aabb);
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst || !inst->make_shadow || !inst->model)
continue;
// Start with the model's AABB, inflated with shadow_volume_bone_radius.
vec3 inst_aabb[2];
glm_vec3_subs(inst->model->aabb[0], inst->shadow_volume_bone_radius, inst_aabb[0]);
glm_vec3_adds(inst->model->aabb[1], inst->shadow_volume_bone_radius, inst_aabb[1]);
// To save CPU cycles, consider only the translation components of bone transforms.
vec3 bone_translation_aabb[2];
glm_aabb_invalidate(bone_translation_aabb);
for (int j = 0; j < inst->model->nr_bones; j++) {
glm_vec3_minv(inst->bone_transforms[j][3], bone_translation_aabb[0], bone_translation_aabb[0]);
glm_vec3_maxv(inst->bone_transforms[j][3], bone_translation_aabb[1], bone_translation_aabb[1]);
}
if (glm_aabb_isvalid(bone_translation_aabb)) {
glm_vec3_add(inst_aabb[0], bone_translation_aabb[0], inst_aabb[0]);
glm_vec3_add(inst_aabb[1], bone_translation_aabb[1], inst_aabb[1]);
}
// Apply local transform.
if (inst->local_transform_needs_update)
RE_instance_update_local_transform(inst);
glm_aabb_transform(inst_aabb, inst->local_transform, inst_aabb);
glm_aabb_merge(inst_aabb, aabb, aabb);
}
if (!glm_aabb_isvalid(aabb))
return false;
// Create a orthographic frustum that contains the AABB.
vec3 center;
glm_aabb_center(aabb, center);
vec3 light_pos;
glm_vec3_scale(plugin->shadow_map_light_dir, -glm_aabb_radius(aabb), light_pos);
glm_vec3_add(light_pos, center, light_pos);
mat4 view_matrix;
vec3 up = {0.0, 1.0, 0.0};
glm_lookat(light_pos, center, up, view_matrix);
mat4 proj_matrix;
glm_aabb_transform(aabb, view_matrix, aabb);
glm_ortho_aabb(aabb, proj_matrix);
glm_mat4_mul(proj_matrix, view_matrix, dest);
return true;
}
static void render_shadow_map(struct RE_plugin *plugin, mat4 light_space_transform)
{
if (!calc_shadow_light_transform(plugin, light_space_transform)) {
// No shadow casters, but proceed anyway to clear the shadow texture.
glm_mat4_identity(light_space_transform);
}
struct RE_renderer *r = plugin->renderer;
GLint orig_fbo, orig_viewport[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_fbo);
glGetIntegerv(GL_VIEWPORT, orig_viewport);
glBindFramebuffer(GL_FRAMEBUFFER, r->shadow.fbo);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(r->shadow.program);
glUniformMatrix4fv(r->shadow.view_transform, 1, GL_FALSE, light_space_transform[0]);
glEnable(GL_DEPTH_TEST);
// Render the shadow casters.
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst || !inst->make_shadow || !inst->model)
continue;
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]);
} else {
glUniform1i(r->shadow.has_bones, GL_FALSE);
}
glUniformMatrix4fv(r->shadow.world_transform, 1, GL_FALSE, inst->local_transform[0]);
for (int j = 0; j < model->nr_meshes; j++) {
struct mesh *mesh = &model->meshes[j];
glBindVertexArray(mesh->vao);
glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices);
}
glBindVertexArray(0);
}
glDisable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo);
glViewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]);
}
static void render_back_cg(struct texture *dst, struct RE_back_cg *bcg, struct RE_renderer *r)
{
if (!bcg->texture.handle)
@@ -360,6 +548,12 @@ void RE_render(struct sact_sprite *sp)
sprite_dirty(sp);
struct texture *texture = sprite_get_texture(sp);
mat4 shadow_transform;
if (plugin->shadow_mode)
render_shadow_map(plugin, shadow_transform);
else
glm_mat4_identity(shadow_transform);
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, texture, 0, 0, texture->w, texture->h);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, r->depth_buffer);
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
@@ -388,9 +582,11 @@ void RE_render(struct sact_sprite *sp)
plugin->proj_transform[1][1] *= -1;
glFrontFace(GL_CW);
glUseProgram(r->shader.program);
glUniformMatrix4fv(r->shader.view_transform, 1, GL_FALSE, view_transform[0]);
glUseProgram(r->program);
glUniformMatrix4fv(r->view_transform, 1, GL_FALSE, view_transform[0]);
glUniformMatrix4fv(r->proj_transform, 1, GL_FALSE, plugin->proj_transform[0]);
glUniformMatrix4fv(r->shadow_transform, 1, GL_FALSE, shadow_transform[0]);
glUniform1f(r->shadow_bias, plugin->shadow_bias);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+102 -15
View File
@@ -285,9 +285,35 @@ static bool ReignEngine_SetInstanceDraw(int plugin, int instance, bool flag)
return true;
}
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawShadow, int plugin, int instance, bool flag);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawBackShadow, int plugin, int instance, bool flag);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawMakeShadow, int plugin, int instance, bool flag);
static bool ReignEngine_SetInstanceDrawShadow(int plugin, int instance, bool flag)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->draw_shadow = flag;
return true;
}
static bool ReignEngine_SetInstanceDrawBackShadow(int plugin, int instance, bool flag)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
if (flag) {
WARNING("DrawBackShaodw is not supported");
return false;
}
return true;
}
static bool ReignEngine_SetInstanceDrawMakeShadow(int plugin, int instance, bool flag)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->make_shadow = flag;
return true;
}
static bool ReignEngine_SetInstanceDrawBump(int plugin, int instance, bool flag)
{
@@ -306,9 +332,23 @@ static bool ReignEngine_GetInstanceDraw(int plugin, int instance)
return ri->draw;
}
//bool ReignEngine_GetInstanceDrawShadow(int plugin, int instance);
static bool ReignEngine_GetInstanceDrawShadow(int plugin, int instance)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
return ri->draw_shadow;
}
//bool ReignEngine_GetInstanceDrawBackShadow(int plugin, int instance);
//bool ReignEngine_GetInstanceDrawMakeShadow(int plugin, int instance);
static bool ReignEngine_GetInstanceDrawMakeShadow(int plugin, int instance)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
return ri->make_shadow;
}
static bool ReignEngine_GetInstanceDrawBump(int plugin, int instance)
{
@@ -486,8 +526,22 @@ static bool ReignEngine_TransInstanceLocalPosToWorldPosByBone(int plugin, int in
HLL_WARN_UNIMPLEMENTED(0.0, float, ReignEngine, CalcInstanceHeightDetection, int plugin, int instance, float x, float z);
//float ReignEngine_GetInstanceSoftFogEdgeLength(int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceSoftFogEdgeLength, int plugin, int instance, float length);
//float ReignEngine_GetInstanceShadowVolumeBoneRadius(int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceShadowVolumeBoneRadius, int plugin, int instance, float radius);
static float ReignEngine_GetInstanceShadowVolumeBoneRadius(int plugin, int instance)
{
struct RE_instance *ri = get_instance(plugin, instance);
return ri ? ri->shadow_volume_bone_radius : 0.0;
}
static bool ReignEngine_SetInstanceShadowVolumeBoneRadius(int plugin, int instance, float radius)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->shadow_volume_bone_radius = radius;
return true;
}
//bool ReignEngine_GetInstanceDebugDrawShadowVolume(int plugin, int instance);
//bool ReignEngine_SetInstanceDebugDrawShadowVolume(int plugin, int instance, bool flag);
//bool ReignEngine_SaveEffect(int plugin, int instance);
@@ -662,11 +716,44 @@ static int ReignEngine_GetShadowMapResolutionLevel(int plugin)
}
//float ReignEngine_GetShadowSplitDepth(int plugin, int num);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetShadowMapType, int plugin, int type);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetShadowMapLightLookPos, int plugin, float x, float y, float z);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetShadowMapLightDir, int plugin, float x, float y, float z);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetShadowBox, int plugin, float x, float y, float z, float size_x, float size_y, float size_z);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetShadowBias, int plugin, int num, float shadow_bias);
static bool ReignEngine_SetShadowMapType(int plugin, int type)
{
// Toushin Toshi 3 uses only type 0.
if (type != 0)
WARNING("non-zero shadow map type is not supported");
return true;
}
HLL_QUIET_UNIMPLEMENTED(true, bool, ReignEngine, SetShadowMapLightLookPos, int plugin, float x, float y, float z); // no-op in shadow map type 0?
static bool ReignEngine_SetShadowMapLightDir(int plugin, float x, float y, float z)
{
struct RE_plugin *p = get_plugin(plugin);
if (!p)
return false;
p->shadow_map_light_dir[0] = x;
p->shadow_map_light_dir[1] = y;
p->shadow_map_light_dir[2] = -z;
glm_vec3_normalize(p->shadow_map_light_dir);
return true;
}
HLL_QUIET_UNIMPLEMENTED(true, bool, ReignEngine, SetShadowBox, int plugin, float x, float y, float z, float size_x, float size_y, float size_z); // no-op in shadow map type 0?
static bool ReignEngine_SetShadowBias(int plugin, int num, float shadow_bias)
{
struct RE_plugin *p = get_plugin(plugin);
if (!p)
return false;
if (num != 0) {
WARNING("SetShadowBias(num=%d): not supported", num);
return false;
}
p->shadow_bias = shadow_bias;
return true;
}
//bool ReignEngine_SetShadowSlopeBias(int plugin, float fShadowSlopeBias);
//bool ReignEngine_SetShadowFilterMag(int plugin, float fShadowFilterMag);
//bool ReignEngine_SetShadowTargetDistance(int plugin, int num, float fDistance);
@@ -1194,9 +1281,9 @@ HLL_LIBRARY(ReignEngine,
HLL_EXPORT(SetInstanceDrawMakeShadow, ReignEngine_SetInstanceDrawMakeShadow),
HLL_EXPORT(SetInstanceDrawBump, ReignEngine_SetInstanceDrawBump),
HLL_EXPORT(GetInstanceDraw, ReignEngine_GetInstanceDraw),
HLL_TODO_EXPORT(GetInstanceDrawShadow, ReignEngine_GetInstanceDrawShadow),
HLL_EXPORT(GetInstanceDrawShadow, ReignEngine_GetInstanceDrawShadow),
HLL_TODO_EXPORT(GetInstanceDrawBackShadow, ReignEngine_GetInstanceDrawBackShadow),
HLL_TODO_EXPORT(GetInstanceDrawMakeShadow, ReignEngine_GetInstanceDrawMakeShadow),
HLL_EXPORT(GetInstanceDrawMakeShadow, ReignEngine_GetInstanceDrawMakeShadow),
HLL_EXPORT(GetInstanceDrawBump, ReignEngine_GetInstanceDrawBump),
HLL_TODO_EXPORT(GetInstanceDrawType, ReignEngine_GetInstanceDrawType),
HLL_EXPORT(SetInstanceDrawType, ReignEngine_SetInstanceDrawType),
@@ -1253,7 +1340,7 @@ HLL_LIBRARY(ReignEngine,
HLL_EXPORT(CalcInstanceHeightDetection, ReignEngine_CalcInstanceHeightDetection),
HLL_TODO_EXPORT(GetInstanceSoftFogEdgeLength, ReignEngine_GetInstanceSoftFogEdgeLength),
HLL_EXPORT(SetInstanceSoftFogEdgeLength, ReignEngine_SetInstanceSoftFogEdgeLength),
HLL_TODO_EXPORT(GetInstanceShadowVolumeBoneRadius, ReignEngine_GetInstanceShadowVolumeBoneRadius),
HLL_EXPORT(GetInstanceShadowVolumeBoneRadius, ReignEngine_GetInstanceShadowVolumeBoneRadius),
HLL_EXPORT(SetInstanceShadowVolumeBoneRadius, ReignEngine_SetInstanceShadowVolumeBoneRadius),
HLL_TODO_EXPORT(GetInstanceDebugDrawShadowVolume, ReignEngine_GetInstanceDebugDrawShadowVolume),
HLL_TODO_EXPORT(SetInstanceDebugDrawShadowVolume, ReignEngine_SetInstanceDebugDrawShadowVolume),
+3 -8
View File
@@ -89,7 +89,7 @@ static GLchar *read_shader_file(const char *path)
return source;
}
static GLuint load_shader_file(const char *path, GLenum type)
GLuint gfx_load_shader_file(const char *path, GLenum type)
{
GLint shader_compiled;
GLuint shader;
@@ -115,16 +115,11 @@ static GLuint load_shader_file(const char *path, GLenum type)
void gfx_load_shader(struct shader *dst, const char *vertex_shader_path, const char *fragment_shader_path)
{
GLuint program = glCreateProgram();
GLuint vertex_shader = load_shader_file(vertex_shader_path, GL_VERTEX_SHADER);
GLuint fragment_shader = load_shader_file(fragment_shader_path, GL_FRAGMENT_SHADER);
GLuint vertex_shader = gfx_load_shader_file(vertex_shader_path, GL_VERTEX_SHADER);
GLuint fragment_shader = gfx_load_shader_file(fragment_shader_path, GL_FRAGMENT_SHADER);
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
// In OpenGL < 3.2, Attribute location 0 is special. Make sure it's assigned
// to the vertex position.
glBindAttribLocation(program, 0, "vertex_pos");
glLinkProgram(program);
GLint link_success;