ReignEngine: Implement basic lighting

This implements a Phong shading with ambient, diffuse and specular
components, using up to three directional lights and one specular light.

The light calculation is made to match the "high quality" 3D mode of
Toushin Toshi 3.
This commit is contained in:
kichikuou
2022-07-09 14:36:44 +09:00
parent b23d05bcc2
commit b42032c9f8
8 changed files with 209 additions and 27 deletions
+9 -4
View File
@@ -91,9 +91,7 @@ struct RE_plugin {
bool use_power2_texture;
int shadow_map_resolution_level;
int texture_resolution_level;
float global_ambient_r;
float global_ambient_g;
float global_ambient_b;
vec3 global_ambient;
float post_effect_filter_y;
float post_effect_filter_cb;
float post_effect_filter_cr;
@@ -108,16 +106,23 @@ struct RE_instance {
enum RE_instance_type type;
vec3 pos;
float pitch, roll, yaw; // in degrees
vec3 vec;
vec3 scale;
float alpha;
bool draw;
float fps;
bool motion_blend;
float motion_blend_rate;
vec3 ambient;
// Lights
vec3 vec;
vec3 diffuse;
vec3 globe_diffuse;
// Private
bool local_transform_needs_update;
mat4 local_transform;
mat3 normal_transform;
mat4 *bone_transforms; // model->nr_bones elements
};
+37 -2
View File
@@ -14,14 +14,49 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#define NR_DIR_LIGHTS 3
struct dir_light {
vec3 dir;
vec3 diffuse;
vec3 globe_diffuse;
};
uniform sampler2D tex;
uniform float alpha_mod;
uniform vec3 ambient;
uniform dir_light dir_lights[NR_DIR_LIGHTS];
uniform vec3 specular_light_dir;
uniform float specular_strength;
uniform float specular_shininess;
uniform vec3 view_pos;
in vec2 tex_coord;
in vec3 normal;
in vec3 frag_pos;
out vec4 frag_color;
void main() {
// TODO: Implement lighting.
vec3 norm = normalize(normal);
vec3 frag_rgb = ambient;
// Diffuse lighting
vec3 diffuse = vec3(0.0);
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
float half_lambert = dot(norm, -dir_lights[i].dir) * 0.5 + 0.5;
diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert);
}
vec4 texel = texture(tex, tex_coord);
frag_color = vec4(texel.rgb, texel.a * alpha_mod);
frag_rgb += texel.rgb * diffuse;
// Specular lighting
if (specular_strength > 0.0) {
vec3 view_dir = normalize(view_pos - frag_pos);
vec3 reflect_dir = reflect(specular_light_dir, norm);
float specular = pow(max(dot(view_dir, reflect_dir), 0.0), specular_shininess) * specular_strength;
frag_rgb += vec3(specular);
}
frag_color = vec4(frag_rgb, texel.a * alpha_mod);
}
+8 -1
View File
@@ -17,6 +17,7 @@
uniform mat4 local_transform;
uniform mat4 view_transform;
uniform mat4 proj_transform;
uniform mat3 normal_transform;
const int MAX_BONES = 211; // see 3d_internal.h
const int NR_WEIGHTS = 4;
@@ -30,6 +31,8 @@ in ivec4 vertex_bone_index;
in vec4 vertex_bone_weight;
out vec2 tex_coord;
out vec3 normal;
out vec3 frag_pos;
void main() {
mat4 bone_transform = mat4(1.0f);
@@ -42,6 +45,10 @@ void main() {
}
}
gl_Position = proj_transform * view_transform * local_transform * bone_transform * vec4(vertex_pos, 1.0);
vec4 world_pos = local_transform * bone_transform * vec4(vertex_pos, 1.0);
gl_Position = proj_transform * view_transform * world_pos;
normal = normal_transform * mat3(bone_transform) * vertex_normal;
tex_coord = vertex_uv;
frag_pos = vec3(world_pos);
}
+13
View File
@@ -24,6 +24,7 @@
#include "gfx/gl.h"
#include "gfx/gfx.h"
#define NR_DIR_LIGHTS 3
#define MAX_BONES 211 // Maximum in TT3
struct model {
@@ -75,9 +76,21 @@ struct RE_renderer {
// Uniform variable locations
GLint local_transform;
GLint proj_transform;
GLint normal_transform;
GLint alpha_mod;
GLint has_bones;
GLint bone_matrices;
GLint ambient;
struct {
GLint dir;
GLint diffuse;
GLint globe_diffuse;
GLint ambient;
} dir_lights[NR_DIR_LIGHTS];
GLint specular_light_dir;
GLint specular_strength;
GLint specular_shininess;
GLint view_pos;
// Attribute variable locations
GLint vertex_normal;
+16 -8
View File
@@ -21,6 +21,8 @@
#include "sprite.h"
#include "xsystem4.h"
#define SPREAD_VEC3(v) (v)[0], (v)[1], (v)[2]
static const char *instance_type_name(enum RE_instance_type type)
{
switch (type) {
@@ -65,17 +67,24 @@ static void print_instance(struct RE_instance *inst, int index, int indent)
indent++;
indent_printf(indent, "type = %s,\n", instance_type_name(inst->type));
indent_printf(indent, "draw = %d,\n", inst->draw);
indent_printf(indent, "pos = {x=%f, y=%f, z=%f},\n", inst->pos[0], inst->pos[1], inst->pos[2]);
indent_printf(indent, "vec = {x=%f, y=%f, z=%f},\n", inst->vec[0], inst->vec[1], inst->vec[2]);
indent_printf(indent, "scale = {x=%f, y=%f, z=%f},\n", inst->scale[0], inst->scale[1], inst->scale[2]);
if (inst->type == RE_ITYPE_DIRECTIONAL_LIGHT || inst->type == RE_ITYPE_SPECULAR_LIGHT) {
indent_printf(indent, "vec = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->vec));
indent_printf(indent, "diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->diffuse));
indent_printf(indent, "globe_diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->globe_diffuse));
} else {
indent_printf(indent, "draw = %d,\n", inst->draw);
indent_printf(indent, "pos = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->pos));
indent_printf(indent, "scale = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->scale));
indent_printf(indent, "ambient = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->ambient));
}
if (inst->model)
indent_printf(indent, "path = \"%s\",\n", inst->model->path);
if (inst->motion)
if (inst->motion) {
indent_printf(indent, "fps = %f,\n", inst->fps);
print_motion("motion", inst->motion, indent);
}
if (inst->next_motion)
print_motion("next_motion", inst->next_motion, indent);
indent_printf(indent, "fps = %f,\n", inst->fps);
if (inst->motion_blend)
indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate);
@@ -109,8 +118,7 @@ void RE_debug_print(struct sact_sprite *sp, int indent)
indent_printf(indent, "name = \"%s\",\n", p->plugin.name);
indent_printf(indent, "camera = {x=%f, y=%f, z=%f, pitch=%f, roll=%f, yaw=%f},\n",
p->camera.pos[0], p->camera.pos[1], p->camera.pos[2],
p->camera.pitch, p->camera.roll, p->camera.yaw);
SPREAD_VEC3(p->camera.pos), p->camera.pitch, p->camera.roll, p->camera.yaw);
for (int i = 0; i < RE_MAX_INSTANCES; i++)
print_instance(p->instances[i], i, indent);
+1
View File
@@ -42,6 +42,7 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin)
instance->alpha = 1.0;
instance->fps = 30.0;
glm_mat4_identity(instance->local_transform);
glm_mat3_identity(instance->normal_transform);
return instance;
}
+82 -1
View File
@@ -65,9 +65,24 @@ struct RE_renderer *RE_renderer_new(struct texture *texture)
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");
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);
sprintf(buf, "dir_lights[%d].diffuse", i);
r->dir_lights[i].diffuse = glGetUniformLocation(r->shader.program, buf);
sprintf(buf, "dir_lights[%d].globe_diffuse", i);
r->dir_lights[i].globe_diffuse = glGetUniformLocation(r->shader.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->view_pos = glGetUniformLocation(r->shader.program, "view_pos");
r->vertex_normal = glGetAttribLocation(r->shader.program, "vertex_normal");
r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv");
r->vertex_bone_index = glGetAttribLocation(r->shader.program, "vertex_bone_index");
@@ -156,6 +171,11 @@ static void update_local_transform(struct RE_instance *inst)
glm_mat4_mul(inst->local_transform, rot, inst->local_transform);
glm_scale(inst->local_transform, inst->scale);
mat3 normal;
glm_mat4_pick3(inst->local_transform, normal);
glm_mat3_inv(normal, normal);
glm_mat3_transpose_to(normal, inst->normal_transform);
inst->local_transform_needs_update = false;
}
@@ -236,12 +256,26 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
update_local_transform(inst);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, inst->local_transform[0]);
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, inst->normal_transform[0]);
glUniform1f(r->alpha_mod, inst->alpha);
vec3 ambient;
glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
glUniform3fv(r->ambient, 1, ambient);
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
struct material *material = &model->materials[mesh->material];
if (inst->plugin->specular_mode) {
glUniform1f(r->specular_strength, material->specular_strength);
glUniform1f(r->specular_shininess, material->specular_shininess);
} else {
glUniform1f(r->specular_strength, 0.0);
glUniform1f(r->specular_shininess, 0.0);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, model->materials[mesh->material].color_map);
glBindTexture(GL_TEXTURE_2D, material->color_map);
glUniform1i(r->shader.texture, 0);
glBindVertexArray(mesh->vao);
@@ -288,10 +322,20 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
glm_mat4_pick3t(view_mat, rot);
glm_mat4_ins3(rot, local_transform);
glm_scale(local_transform, inst->scale);
mat3 normal_transform;
// This should be safe because billboards do not have non-uniform scaling.
glm_mat4_pick3(local_transform, normal_transform);
vec3 ambient;
glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
glUniform3fv(r->ambient, 1, ambient);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, normal_transform[0]);
glUniform1i(r->has_bones, GL_FALSE);
glUniform1f(r->alpha_mod, inst->alpha);
glUniform1f(r->specular_strength, 0.0);
glUniform1f(r->specular_shininess, 0.0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bt->texture);
@@ -313,6 +357,41 @@ static void render_back_cg(struct texture *dst, struct RE_back_cg *bcg, struct R
gfx_copy_stretch_blend(dst, bcg->x, bcg->y, sw * bcg->mag, sh * bcg->mag, &bcg->texture, 0, 0, sw, sh, bcg->blend_rate * 255);
}
static void setup_lights(struct RE_plugin *plugin)
{
struct RE_renderer *r = plugin->renderer;
glUniform3fv(r->view_pos, 1, plugin->camera.pos);
int light_index = 0;
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst)
continue;
switch (inst->type) {
case RE_ITYPE_DIRECTIONAL_LIGHT:
if (light_index >= NR_DIR_LIGHTS) {
WARNING("too many directional lights");
break;
}
glUniform3fv(r->dir_lights[light_index].dir, 1, inst->vec);
glUniform3fv(r->dir_lights[light_index].diffuse, 1, inst->diffuse);
glUniform3fv(r->dir_lights[light_index].globe_diffuse, 1, inst->globe_diffuse);
light_index++;
break;
case RE_ITYPE_SPECULAR_LIGHT:
glUniform3fv(r->specular_light_dir, 1, inst->vec);
break;
default:
break;
}
}
for (; light_index < NR_DIR_LIGHTS; light_index++) {
const vec3 zero = {0.0, 0.0, 0.0};
glUniform3fv(r->dir_lights[light_index].dir, 1, zero);
glUniform3fv(r->dir_lights[light_index].diffuse, 1, zero);
glUniform3fv(r->dir_lights[light_index].globe_diffuse, 1, zero);
}
}
void RE_render(struct sact_sprite *sp)
{
uint32_t timestamp = SDL_GetTicks();
@@ -363,6 +442,8 @@ void RE_render(struct sact_sprite *sp)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
setup_lights(plugin);
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst || !inst->draw)
+43 -11
View File
@@ -14,6 +14,7 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <cglm/cglm.h>
#include <stdlib.h>
#include "system4.h"
@@ -135,6 +136,7 @@ static bool ReignEngine_SetInstanceVector(int plugin, int instance, float x, flo
ri->vec[0] = x;
ri->vec[1] = y;
ri->vec[2] = -z;
glm_vec3_normalize(ri->vec);
return true;
}
@@ -219,14 +221,44 @@ static bool ReignEngine_SetInstanceScaleZ(int plugin, int instance, float scale_
//bool ReignEngine_SetInstanceZBias(int plugin, int instance, float fZBias);
//float ReignEngine_GetInstanceZBias(int plugin, int instance);
bool ReignEngine_SetInstanceVertexPos(int plugin, int instance, int index, float x, float y, float z)
static bool ReignEngine_SetInstanceVertexPos(int plugin, int instance, int index, float x, float y, float z)
{
return RE_instance_set_vertex_pos(get_instance(plugin, instance), index, x, y, z);
}
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDiffuse, int plugin, int instance, float r, float g, float b);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceGlobeDiffuse, int plugin, int instance, float r, float g, float b);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceAmbient, int plugin, int instance, float r, float g, float b);
static bool ReignEngine_SetInstanceDiffuse(int plugin, int instance, float r, float g, float b)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->diffuse[0] = r;
ri->diffuse[1] = g;
ri->diffuse[2] = b;
return true;
}
static bool ReignEngine_SetInstanceGlobeDiffuse(int plugin, int instance, float r, float g, float b)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->globe_diffuse[0] = r;
ri->globe_diffuse[1] = g;
ri->globe_diffuse[2] = b;
return true;
}
static bool ReignEngine_SetInstanceAmbient(int plugin, int instance, float r, float g, float b)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->ambient[0] = r;
ri->ambient[1] = g;
ri->ambient[2] = b;
return true;
}
//bool ReignEngine_SetInstanceSpecular(int plugin, int instance, float fSpecular);
static bool ReignEngine_SetInstanceAlpha(int plugin, int instance, float alpha)
@@ -882,9 +914,9 @@ static bool ReignEngine_GetGlobalAmbient(int plugin, float *r, float *g, float *
struct RE_plugin *p = get_plugin(plugin);
if (!p)
return false;
*r = p->global_ambient_r;
*g = p->global_ambient_g;
*b = p->global_ambient_b;
*r = p->global_ambient[0];
*g = p->global_ambient[1];
*b = p->global_ambient[2];
return true;
}
@@ -893,9 +925,9 @@ static bool ReignEngine_SetGlobalAmbient(int plugin, float r, float g, float b)
struct RE_plugin *p = get_plugin(plugin);
if (!p)
return false;
p->global_ambient_r = r;
p->global_ambient_g = g;
p->global_ambient_b = b;
p->global_ambient[0] = r;
p->global_ambient[1] = g;
p->global_ambient[2] = b;
return true;
}
@@ -1085,7 +1117,7 @@ HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, IsLoading, int plugin);
//bool ReignEngine_SetDebugInfoMode(int plugin, int nMode);
HLL_WARN_UNIMPLEMENTED(30, int, ReignEngine, GetVertexShaderVersion, void);
HLL_WARN_UNIMPLEMENTED(30, int, ReignEngine, GetPixelShaderVersion, void);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceSpecularReflectRate, int plugin, int instance, float rate);
HLL_QUIET_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceSpecularReflectRate, int plugin, int instance, float rate); // the value is unused?
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceFresnelReflectRate, int plugin, int instance, float rate);
//float ReignEngine_GetInstanceSpecularReflectRate(int plugin, int instance);
//float ReignEngine_GetInstanceFresnelReflectRate(int plugin, int instance);