pbr: refactor material management and shader

Introduced a new PBRMaterial resource type. Materials are now fully
described with .material files instead of being hardcoded. Added some
functions to abstract away and simplify set up of PBR shaders.
This commit is contained in:
Andrei Alexeyev 2021-07-10 05:09:08 +03:00
parent 507080c604
commit 78266ace3f
No known key found for this signature in database
GPG key ID: 72D26128040B9690
37 changed files with 707 additions and 232 deletions

View file

@ -0,0 +1,5 @@
ambient_map = credits/tower_ambient
diffuse_map = credits/tower_diffuse
normal_map = credits/tower_normal
roughness_map = credits/tower_roughness

View file

@ -0,0 +1,6 @@
diffuse_map = stage2/branch_diffuse
normal_map = stage2/branch_normal
ambient_map = stage2/branch_ambient
roughness_map = stage2/branch_roughness

View file

@ -0,0 +1,6 @@
diffuse_map = stage2/grass_diffuse
normal_map = stage2/grass_normal
ambient_map = stage2/grass_ambient
roughness_map = stage2/grass_roughness

View file

@ -0,0 +1,6 @@
diffuse_map = stage2/ground_diffuse
normal_map = stage2/ground_normal
ambient_map = stage2/ground_ambient
roughness_map = stage2/ground_roughness

View file

@ -0,0 +1,6 @@
diffuse_map = stage2/leaves_diffuse
normal_map = stage2/leaves_normal
ambient_map = stage2/leaves_ambient
roughness_map = stage2/leaves_roughness

View file

@ -0,0 +1,6 @@
diffuse_map = stage2/rocks_diffuse
normal_map = stage2/rocks_normal
ambient_map = stage2/rocks_ambient
roughness_map = stage2/rocks_roughness

View file

@ -0,0 +1,5 @@
ambient_map = stage3/ground_ambient
diffuse_map = stage3/ground_diffuse
normal_map = stage3/ground_normal
roughness_map = stage3/ground_roughness

View file

@ -0,0 +1,5 @@
ambient_map = stage3/leaves_ambient
diffuse_map = stage3/leaves_diffuse
normal_map = stage3/leaves_normal
roughness_map = stage3/leaves_roughness

View file

@ -0,0 +1,5 @@
ambient_map = stage3/rocks_ambient
diffuse_map = stage3/rocks_diffuse
normal_map = stage3/rocks_normal
roughness_map = stage3/rocks_roughness

View file

@ -0,0 +1,5 @@
ambient_map = stage3/trees_ambient
diffuse_map = stage3/trees_diffuse
normal_map = stage3/trees_normal
roughness_map = stage3/trees_roughness

View file

@ -0,0 +1,5 @@
ambient_map = stage4/corridor_ambient
diffuse_map = stage4/corridor_diffuse
normal_map = stage4/corridor_normal
roughness_map = stage4/corridor_roughness

View file

@ -0,0 +1,5 @@
ambient_map = stage4/ground_ambient
diffuse_map = stage4/ground_diffuse
normal_map = stage4/ground_normal
roughness_map = stage4/ground_roughness

View file

@ -0,0 +1,5 @@
ambient_map = stage4/mansion_ambient
diffuse_map = stage4/mansion_diffuse
normal_map = stage4/mansion_normal
roughness_map = stage4/mansion_roughness

View file

@ -4,14 +4,29 @@
#include "standard.glslh"
#include "../lib/pbr.glslh"
UNIFORM(1) sampler2D roughness_map;
UNIFORM(2) sampler2D normal_map;
UNIFORM(3) sampler2D ambient_map;
UNIFORM(4) float metallic;
UNIFORM(5) vec3 ambient_color; // modulates ambient map
UNIFORM(6) int light_count;
UNIFORM(7) vec3 light_positions[PBR_MAX_LIGHTS];
UNIFORM(13) vec3 light_colors[PBR_MAX_LIGHTS]; // layout-id also depends on PBR_MAX_LIGHTS
#define PBR_FEATURE_DIFFUSE_MAP 1
#define PBR_FEATURE_NORMAL_MAP 2
#define PBR_FEATURE_AMBIENT_MAP 4
#define PBR_FEATURE_ROUGHNESS_MAP 8
#define PBR_FEATURE_ENVIRONMENT_MAP 16
UNIFORM(1) int features_mask;
UNIFORM(2) sampler2D diffuse_map;
UNIFORM(3) sampler2D normal_map;
UNIFORM(4) sampler2D ambient_map;
UNIFORM(5) sampler2D roughness_map;
UNIFORM(6) samplerCube environment_map;
// These either modulate their respective maps, or are used instead of them
UNIFORM(7) vec4 diffuseRGB_metallicA;
UNIFORM(8) vec4 ambientRGB_roughnessA;
UNIFORM(11) mat4 inv_camera_transform; // only used if PBR_FEATURE_ENVIRONMENT_MAP is set
UNIFORM(12) int light_count;
UNIFORM(13) vec3 light_positions[PBR_MAX_LIGHTS];
UNIFORM(19) vec3 light_colors[PBR_MAX_LIGHTS]; // layout-id also depends on PBR_MAX_LIGHTS
VARYING(3) vec3 pos;
VARYING(4) vec3 tangent;

View file

@ -4,23 +4,51 @@
#include "interface/pbr.glslh"
void main(void) {
vec4 roughness_sample = texture(roughness_map, texCoord);
float alpha = roughness_sample.a;
float roughness = ambientRGB_roughnessA.a;
float alpha;
if(alpha < 0.3) {
discard;
if(bool(features_mask & PBR_FEATURE_ROUGHNESS_MAP)) {
vec4 roughness_sample = texture(roughness_map, texCoord);
roughness *= roughness_sample.r;
alpha = roughness_sample.a;
// TODO: a way to opt out of this, since it hurts performance.
if(alpha < 0.3) {
discard;
}
} else {
alpha = 1.0;
}
float metallic = diffuseRGB_metallicA.a;
vec3 diffuse = diffuseRGB_metallicA.rgb;
if(bool(features_mask & PBR_FEATURE_DIFFUSE_MAP)) {
diffuse *= texture(diffuse_map, texCoord).rgb;
}
vec3 ambient = ambientRGB_roughnessA.rgb;
if(bool(features_mask & PBR_FEATURE_AMBIENT_MAP)) {
ambient *= texture(ambient_map, texCoord).rgb;
}
vec3 tbn_normal;
if(bool(features_mask & PBR_FEATURE_NORMAL_MAP)) {
tbn_normal = sample_normalmap(normal_map, texCoord);
} else {
tbn_normal = vec3(0, 0, 1);
}
vec3 ambient = texture(ambient_map, texCoord).rgb;
vec3 tbn_normal = sample_normalmap(normal_map, texCoord);
mat3 tbn = mat3(normalize(tangent), normalize(bitangent), normalize(normal));
PBRParams p;
p.fragPos = pos;
p.albedo = r_color.rgb * texture(tex, texCoord).rgb;
p.roughness = roughness_sample.r;
p.albedo = diffuse;
p.roughness = roughness;
p.metallic = metallic;
p.normal = normalize(tbn * tbn_normal);
p.normal = tbn * tbn_normal;
PBRState pbr = PBR(p);
@ -29,9 +57,17 @@ void main(void) {
Lo += PBR_PointLight(pbr, PointLight(light_positions[i], light_colors[i]));
}
vec3 color = ambient * ambient_color + Lo;
vec3 color = ambient + Lo;
if(bool(features_mask & PBR_FEATURE_ENVIRONMENT_MAP)) {
vec3 reflected_ray = mat3(inv_camera_transform) * reflect(pos, p.normal);
vec3 reflection = texture(environment_map, fixCubeCoord(reflected_ray)).rgb;
float r = (1 - p.roughness);
color += (r * r) * reflection * mix(vec3(0.5), p.albedo, p.metallic);
}
color = PBR_TonemapReinhard(color);
color = PBR_GammaCorrect(color);
fragColor = vec4(color, 1) * alpha;
fragColor = vec4(color * alpha, alpha);
}

View file

@ -26,6 +26,7 @@ if host_machine.system() == 'emscripten'
'gfx/*.ani',
'gfx/*.spr',
'gfx/*.tex',
'gfx/*.material',
'fonts/*.font',
'models/*.iqm',

67
scripts/automaterials.py Executable file
View file

@ -0,0 +1,67 @@
#!/usr/bin/env python3
import re
from pathlib import Path
from collections import defaultdict
from taiseilib.common import (
run_main,
)
mat_re = re.compile(r'(.*)_(diffuse|normal|ambient|roughness)\.(?:tex|basis|png|webp)$')
def main(args):
resdir = Path(__file__).parent.parent / 'resources'
materials = defaultdict(set)
gfxdirs = []
for pkgdir in resdir.glob('*.pkgdir'):
gfx = pkgdir / 'gfx'
if not gfx.is_dir():
continue
gfxdirs.append(gfx)
print(gfx)
for p in gfx.glob('**/*'):
rel = p.relative_to(gfx)
m = mat_re.match(str(rel))
if m is None:
continue
matname, mapname = m.groups()
materials[matname].add(mapname)
gfxmain = gfxdirs[0]
for mat, maps in materials.items():
mat_filename = f'{mat}.material'
skip = False
for gfx in gfxdirs:
if (gfx / mat_filename).exists():
print(' - Skip', mat_filename)
skip = True
break
if skip:
continue
outpath = (gfxmain / mat_filename).resolve()
lines = ['']
for mapname in sorted(maps):
lines.append(f'{mapname}_map = {mat}_{mapname}')
lines.append('')
print(' * Write', outpath)
outpath.write_text('\n'.join(lines))
if __name__ == '__main__':
run_main(main)

119
src/resource/material.c Normal file
View file

@ -0,0 +1,119 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "material.h"
static char *material_path(const char *basename);
static bool material_check_path(const char *path);
static void material_load_stage1(ResourceLoadState *st);
ResourceHandler material_res_handler = {
.type = RES_MATERIAL,
.typename = "material",
.subdir = MATERIAL_PATH_PREFIX,
.procs = {
.find = material_path,
.check = material_check_path,
.load = material_load_stage1,
.unload = free,
},
};
static char *material_path(const char *basename) {
return try_path(MATERIAL_PATH_PREFIX, basename, MATERIAL_EXTENSION);
}
static bool material_check_path(const char *path) {
return strendswith(path, MATERIAL_EXTENSION);
}
struct mat_load_data {
PBRMaterial *mat;
union {
struct {
char *diffuse_map;
char *normal_map;
char *ambient_map;
char *roughness_map;
};
char *maps[4];
};
};
static void free_mat_load_data(struct mat_load_data *ld) {
for(int i = 0; i < ARRAY_SIZE(ld->maps); ++i) {
free(ld->maps[i]);
}
free(ld);
}
static void material_load_stage2(ResourceLoadState *st);
static void material_load_stage1(ResourceLoadState *st) {
struct mat_load_data *ld = calloc(1, sizeof(*ld));
ld->mat = calloc(1, sizeof(*ld->mat));
*ld->mat = (PBRMaterial) {
.diffuse_color = { 1, 1, 1 },
.ambient_color = { 1, 1, 1 },
.roughness_value = 1,
.metallic_value = 0,
};
if(!parse_keyvalue_file_with_spec(st->path, (KVSpec[]) {
{ "diffuse_map", .out_str = &ld->diffuse_map },
{ "normal_map", .out_str = &ld->normal_map },
{ "ambient_map", .out_str = &ld->ambient_map },
{ "roughness_map", .out_str = &ld->roughness_map },
{ "diffuse_color", .callback = kvparser_vec3, .callback_data = ld->mat->diffuse_color },
{ "ambient_color", .callback = kvparser_vec3, .callback_data = ld->mat->ambient_color },
{ "roughness", .out_float = &ld->mat->roughness_value },
{ "metallic", .out_float = &ld->mat->metallic_value },
})) {
free_mat_load_data(ld);
log_error("Failed to parse material file '%s'", st->path);
res_load_failed(st);
return;
}
for(int i = 0; i < ARRAY_SIZE(ld->maps); ++i) {
if(ld->maps[i]) {
res_load_dependency(st, RES_TEXTURE, ld->maps[i]);
}
}
res_load_continue_after_dependencies(st, material_load_stage2, ld);
}
#define LOADMAP(_map_) do { \
if(ld->_map_##_map) { \
ld->mat->_map_##_map = get_resource_data(RES_TEXTURE, ld->_map_##_map, st->flags); \
if(UNLIKELY(ld->mat->_map_##_map == NULL)) { \
log_fatal("%s: failed to load " #_map_ " map '%s'", st->name, ld->_map_##_map); \
free_mat_load_data(ld); \
res_load_failed(st); \
} \
} \
} while(0)
static void material_load_stage2(ResourceLoadState *st) {
struct mat_load_data *ld = st->opaque;
LOADMAP(diffuse);
LOADMAP(normal);
LOADMAP(ambient);
LOADMAP(roughness);
res_load_finished(st, ld->mat);
free_mat_load_data(ld);
}

33
src/resource/material.h Normal file
View file

@ -0,0 +1,33 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#pragma once
#include "taisei.h"
#include "resource.h"
#include "texture.h"
typedef struct PBRMaterial {
Texture *diffuse_map;
Texture *normal_map;
Texture *ambient_map;
Texture *roughness_map;
vec3 diffuse_color;
vec3 ambient_color;
float roughness_value;
float metallic_value;
} PBRMaterial;
extern ResourceHandler material_res_handler;
#define MATERIAL_PATH_PREFIX "res/gfx/"
#define MATERIAL_EXTENSION ".material"
DEFINE_RESOURCE_GETTER(PBRMaterial, res_material, RES_MATERIAL)
DEFINE_OPTIONAL_RESOURCE_GETTER(PBRMaterial, res_material_optional, RES_MATERIAL)

View file

@ -3,6 +3,7 @@ resource_src = files(
'animation.c',
'bgm.c',
'font.c',
'material.c',
'model.c',
'postprocess.c',
'resource.c',

View file

@ -15,30 +15,32 @@
#include "events.h"
#include "taskmanager.h"
#include "texture.h"
#include "animation.h"
#include "sfx.h"
#include "bgm.h"
#include "shader_object.h"
#include "shader_program.h"
#include "font.h"
#include "material.h"
#include "model.h"
#include "postprocess.h"
#include "sfx.h"
#include "shader_object.h"
#include "shader_program.h"
#include "sprite.h"
#include "font.h"
#include "texture.h"
#include "renderer/common/backend.h"
ResourceHandler *_handlers[] = {
[RES_TEXTURE] = &texture_res_handler,
[RES_ANIM] = &animation_res_handler,
[RES_SFX] = &sfx_res_handler,
[RES_BGM] = &bgm_res_handler,
[RES_MODEL] = &model_res_handler,
[RES_POSTPROCESS] = &postprocess_res_handler,
[RES_SPRITE] = &sprite_res_handler,
[RES_FONT] = &font_res_handler,
[RES_SHADER_OBJECT] = &shader_object_res_handler,
[RES_SHADER_PROGRAM] = &shader_program_res_handler,
[RES_ANIM] = &animation_res_handler,
[RES_BGM] = &bgm_res_handler,
[RES_FONT] = &font_res_handler,
[RES_MATERIAL] = &material_res_handler,
[RES_MODEL] = &model_res_handler,
[RES_POSTPROCESS] = &postprocess_res_handler,
[RES_SFX] = &sfx_res_handler,
[RES_SHADER_OBJECT] = &shader_object_res_handler,
[RES_SHADER_PROGRAM] = &shader_program_res_handler,
[RES_SPRITE] = &sprite_res_handler,
[RES_TEXTURE] = &texture_res_handler,
};
typedef enum ResourceStatus {

View file

@ -22,6 +22,7 @@ typedef enum ResourceType {
RES_POSTPROCESS,
RES_SPRITE,
RES_FONT,
RES_MATERIAL,
RES_NUMTYPES,
} ResourceType;

View file

@ -22,11 +22,9 @@ Stage2DrawData *stage2_get_draw_data(void) {
}
#define STAGE2_MAX_LIGHTS 4
static void stage2_bg_setup_pbr_lighting(int max_lights) {
static void stage2_bg_setup_pbr_lighting(Camera3D *cam, int max_lights) {
// FIXME: Instead of calling this for each segment, maybe set up the lighting once for the whole scene?
Camera3D *cam = &stage_3d_context.cam;
PointLight3D lights[STAGE2_MAX_LIGHTS] = {
{ { 100, cam->pos[1] - 100, 100 }, { 50000, 50000, 50000 } },
{ { 0, 0, 0 }, { 1, 0, 30 } },
@ -59,7 +57,11 @@ static void stage2_bg_setup_pbr_lighting(int max_lights) {
}
camera3d_set_point_light_uniforms(cam, imin(max_lights, ARRAY_SIZE(lights)), lights);
r_uniform_vec3("ambient_color", 0.5, 0.5, 0.5);
}
static void stage2_bg_setup_pbr_env(Camera3D *cam, int max_lights, PBREnvironment *env) {
stage2_bg_setup_pbr_lighting(cam, max_lights);
glm_vec3_broadcast(0.5f, env->ambient_color);
}
static void stage2_branch_mv_transform(vec3 pos) {
@ -78,16 +80,13 @@ static void stage2_bg_branch_draw(vec3 pos) {
stage2_branch_mv_transform(pos);
r_shader("pbr");
stage2_bg_setup_pbr_lighting(1);
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage2/branch_diffuse");
r_uniform_sampler("roughness_map", "stage2/branch_roughness");
r_uniform_sampler("normal_map", "stage2/branch_normal");
r_uniform_sampler("ambient_map", "stage2/branch_ambient");
r_draw_model("stage2/branch");
PBREnvironment env = { 0 };
stage2_bg_setup_pbr_env(&stage_3d_context.cam, 1, &env);
pbr_draw_model(&stage2_draw_data->models.branch, &env);
r_mat_mv_pop();
r_state_pop();
}
@ -100,16 +99,13 @@ static void stage2_bg_leaves_draw(vec3 pos) {
stage2_branch_mv_transform(pos);
r_shader("pbr");
stage2_bg_setup_pbr_lighting(1);
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage2/leaves_diffuse");
r_uniform_sampler("roughness_map", "stage2/leaves_roughness");
r_uniform_sampler("normal_map", "stage2/leaves_normal");
r_uniform_sampler("ambient_map", "stage2/leaves_ambient");
r_draw_model("stage2/leaves");
PBREnvironment env = { 0 };
stage2_bg_setup_pbr_env(&stage_3d_context.cam, 1, &env);
pbr_draw_model(&stage2_draw_data->models.leaves, &env);
r_mat_mv_pop();
r_state_pop();
}
@ -126,9 +122,10 @@ static void stage2_bg_grass_draw(vec3 pos) {
r_mat_mv_scale(2, 2, 2);
ShaderProgram *sprite_shader = res_shader("sprite_pbr");
r_shader_ptr(sprite_shader);
stage2_bg_setup_pbr_lighting(STAGE2_MAX_LIGHTS);
PBREnvironment env = { 0 };
stage2_bg_setup_pbr_env(&stage_3d_context.cam, STAGE2_MAX_LIGHTS, &env);
r_disable(RCAP_CULL_FACE);
// r_disable(RCAP_DEPTH_WRITE);
@ -169,20 +166,11 @@ static void stage2_bg_ground_draw(vec3 pos) {
r_mat_mv_translate(pos[0], pos[1], pos[2]);
r_shader("pbr");
stage2_bg_setup_pbr_lighting(STAGE2_MAX_LIGHTS);
PBREnvironment env = { 0 };
stage2_bg_setup_pbr_env(&stage_3d_context.cam, STAGE2_MAX_LIGHTS, &env);
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage2/rocks_diffuse");
r_uniform_sampler("roughness_map", "stage2/rocks_roughness");
r_uniform_sampler("normal_map", "stage2/rocks_normal");
r_uniform_sampler("ambient_map", "stage2/rocks_ambient");
r_draw_model("stage2/rocks");
r_uniform_sampler("tex", "stage2/ground_diffuse");
r_uniform_sampler("roughness_map", "stage2/ground_roughness");
r_uniform_sampler("normal_map", "stage2/ground_normal");
r_uniform_sampler("ambient_map", "stage2/ground_ambient");
r_draw_model("stage2/ground");
pbr_draw_model(&stage2_draw_data->models.rocks, &env);
pbr_draw_model(&stage2_draw_data->models.ground, &env);
r_mat_mv_pop();
r_state_pop();
@ -195,15 +183,11 @@ static void stage2_bg_ground_grass_draw(vec3 pos) {
r_mat_mv_translate(pos[0], pos[1], pos[2]);
r_shader("pbr");
stage2_bg_setup_pbr_lighting(STAGE2_MAX_LIGHTS);
PBREnvironment env = { 0 };
stage2_bg_setup_pbr_env(&stage_3d_context.cam, STAGE2_MAX_LIGHTS, &env);
glm_vec3_broadcast(0.4f, env.ambient_color);
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage2/grass_diffuse");
r_uniform_sampler("roughness_map", "stage2/grass_roughness");
r_uniform_sampler("normal_map", "stage2/grass_normal");
r_uniform_sampler("ambient_map", "stage2/grass_ambient");
r_uniform_vec3("ambient_color", 0.4, 0.4, 0.4);
r_draw_model("stage2/grass");
pbr_draw_model(&stage2_draw_data->models.grass, &env);
r_mat_mv_pop();
r_state_pop();
@ -296,6 +280,12 @@ void stage2_drawsys_init(void) {
stage_3d_context.cam.near = 1;
stage_3d_context.cam.far = 60;
stage2_draw_data = calloc(1, sizeof(*stage2_draw_data));
pbr_load_model(&stage2_draw_data->models.branch, "stage2/branch", "stage2/branch");
pbr_load_model(&stage2_draw_data->models.grass, "stage2/grass", "stage2/grass");
pbr_load_model(&stage2_draw_data->models.ground, "stage2/ground", "stage2/ground");
pbr_load_model(&stage2_draw_data->models.leaves, "stage2/leaves", "stage2/leaves");
pbr_load_model(&stage2_draw_data->models.rocks, "stage2/rocks", "stage2/rocks");
}
void stage2_drawsys_shutdown(void) {

View file

@ -10,12 +10,21 @@
#include "taisei.h"
#include "stagedraw.h"
#include "stageutils.h"
typedef struct Stage2DrawData {
struct {
Color color;
} fog;
struct {
PBRModel branch;
PBRModel grass;
PBRModel ground;
PBRModel leaves;
PBRModel rocks;
} models;
real hina_lights;
} Stage2DrawData;

View file

@ -78,36 +78,23 @@ static void stage2_preload(void) {
"part/blast_huge_rays",
NULL);
preload_resources(RES_TEXTURE, RESF_DEFAULT,
"stage2/ground_diffuse",
"stage2/ground_roughness",
"stage2/ground_normal",
"stage2/ground_ambient",
"stage2/branch_diffuse",
"stage2/branch_roughness",
"stage2/branch_normal",
"stage2/branch_ambient",
"stage2/leaves_diffuse",
"stage2/leaves_roughness",
"stage2/leaves_normal",
"stage2/leaves_ambient",
"stage2/rocks_diffuse",
"stage2/rocks_roughness",
"stage2/rocks_normal",
"stage2/rocks_ambient",
"stage2/grass_diffuse",
"stage2/grass_roughness",
"stage2/grass_normal",
"stage2/grass_ambient",
"stage2/water_floor",
"stage2/spellbg1",
"stage2/spellbg2",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
"stage2/ground",
"stage2/rocks",
preload_resources(RES_MATERIAL, RESF_DEFAULT,
"stage2/branch",
"stage2/leaves",
"stage2/grass",
"stage2/ground",
"stage2/leaves",
"stage2/rocks",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
"stage2/branch",
"stage2/grass",
"stage2/ground",
"stage2/leaves",
"stage2/rocks",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"stage1_water",

View file

@ -17,6 +17,12 @@
MODERNIZE_THIS_FILE_AND_REMOVE_ME
static Stage3DrawData *stage3_draw_data;
Stage3DrawData *stage3_get_draw_data(void) {
return NOT_NULL(stage3_draw_data);
}
static uint stage3_bg_pos(Stage3D *s3d, vec3 pos, float maxrange) {
vec3 p = {
0,
@ -29,8 +35,7 @@ static uint stage3_bg_pos(Stage3D *s3d, vec3 pos, float maxrange) {
return linear3dpos(s3d, pos, maxrange, p, r);
}
static void stage3_bg_setup_pbr_lighting(void) {
Camera3D *cam = &stage_3d_context.cam;
static void stage3_bg_setup_pbr_lighting(Camera3D *cam) {
PointLight3D lights[] = {
// TODO animate colors
{ { 0, 0, 10000 }, { 10, 42, 30 } },
@ -60,44 +65,29 @@ static void stage3_bg_setup_pbr_lighting(void) {
}
camera3d_set_point_light_uniforms(cam, ARRAY_SIZE(lights), lights);
}
real f = 1/(1+global.frames/1000.);
r_uniform_vec3("ambient_color",f,f,sqrt(f));
static void stage3_bg_setup_pbr_env(Camera3D *cam, PBREnvironment *env) {
stage3_bg_setup_pbr_lighting(cam);
float f = 1.0f / (1.0f + global.frames / 1000.0f);
glm_vec3_copy((vec3) { f, f, sqrtf(f) }, env->ambient_color);
}
static void stage3_bg_ground_draw(vec3 pos) {
r_state_push();
r_mat_mv_push();
r_mat_mv_translate(pos[0], pos[1], pos[2]);
r_mat_mv_translate_v(pos);
r_shader("pbr");
//r_uniform_vec3_array("light_positions[0]", 0, 1, &stage_3d_context.cx);
stage3_bg_setup_pbr_lighting();
PBREnvironment env = { 0 };
stage3_bg_setup_pbr_env(&stage_3d_context.cam, &env);
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage3/ground_diffuse");
r_uniform_sampler("roughness_map", "stage3/ground_roughness");
r_uniform_sampler("normal_map", "stage3/ground_normal");
r_uniform_sampler("ambient_map", "stage3/ground_ambient");
pbr_draw_model(&stage3_draw_data->models.ground, &env);
pbr_draw_model(&stage3_draw_data->models.trees, &env);
pbr_draw_model(&stage3_draw_data->models.rocks, &env);
r_draw_model("stage3/ground");
r_uniform_sampler("tex", "stage3/trees_diffuse");
r_uniform_sampler("roughness_map", "stage3/trees_roughness");
r_uniform_sampler("normal_map", "stage3/trees_normal");
r_uniform_sampler("ambient_map", "stage3/trees_ambient");
r_draw_model("stage3/trees");
r_uniform_sampler("tex", "stage3/rocks_diffuse");
r_uniform_sampler("roughness_map", "stage3/rocks_roughness");
r_uniform_sampler("normal_map", "stage3/rocks_normal");
r_uniform_sampler("ambient_map", "stage3/rocks_ambient");
r_draw_model("stage3/rocks");
r_mat_mv_pop();
r_state_pop();
}
@ -105,22 +95,15 @@ static void stage3_bg_ground_draw(vec3 pos) {
static void stage3_bg_leaves_draw(vec3 pos) {
r_state_push();
r_mat_mv_push();
r_mat_mv_translate(pos[0], pos[1], pos[2]);
r_mat_mv_translate(0,0,-0.0002);
r_mat_mv_translate_v(pos);
r_mat_mv_translate(0, 0, -0.0002);
r_shader("pbr");
stage3_bg_setup_pbr_lighting();
PBREnvironment env = { 0 };
stage3_bg_setup_pbr_env(&stage_3d_context.cam, &env);
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage3/leaves_diffuse");
r_uniform_sampler("roughness_map", "stage3/leaves_roughness");
r_uniform_sampler("normal_map", "stage3/leaves_normal");
r_uniform_sampler("ambient_map", "stage3/leaves_ambient");
r_draw_model("stage3/leaves");
pbr_draw_model(&stage3_draw_data->models.leaves, &env);
r_mat_mv_pop();
r_state_pop();
@ -132,10 +115,17 @@ void stage3_drawsys_init(void) {
stage_3d_context.cam.rot.v[0] = 80;
stage_3d_context.cam.vel[1] = 0.1;
stage_3d_context.cam.vel[2] = 0.05;
stage3_draw_data = calloc(1, sizeof(*stage3_draw_data));
pbr_load_model(&stage3_draw_data->models.ground, "stage3/ground", "stage3/ground"); pbr_load_model(&stage3_draw_data->models.leaves, "stage3/leaves", "stage3/leaves");
pbr_load_model(&stage3_draw_data->models.rocks, "stage3/rocks", "stage3/rocks");
pbr_load_model(&stage3_draw_data->models.trees, "stage3/trees", "stage3/trees");
}
void stage3_drawsys_shutdown(void) {
stage3d_shutdown(&stage_3d_context);
free(stage3_draw_data);
}
static bool stage3_fog(Framebuffer *fb) {

View file

@ -11,6 +11,19 @@
#include "util/fbpair.h"
#include "stagedraw.h"
#include "stageutils.h"
typedef struct Stage3DrawData {
struct {
PBRModel ground;
PBRModel leaves;
PBRModel rocks;
PBRModel trees;
} models;
} Stage3DrawData;
Stage3DrawData *stage3_get_draw_data(void)
attr_returns_nonnull attr_returns_max_aligned;
void stage3_drawsys_init(void);
void stage3_drawsys_shutdown(void);

View file

@ -86,34 +86,24 @@ static void stage3_preload(void) {
portrait_preload_base_sprite("scuttle", NULL, RESF_DEFAULT);
portrait_preload_face_sprite("scuttle", "normal", RESF_DEFAULT);
preload_resources(RES_BGM, RESF_OPTIONAL, "stage3", "stage3boss", NULL);
preload_resources(RES_SPRITE, RESF_DEFAULT,
"stage3/ground_ambient",
"stage3/ground_normal",
"stage3/ground_roughness",
"stage3/ground_diffuse",
"stage3/trees_ambient",
"stage3/trees_normal",
"stage3/trees_roughness",
"stage3/trees_diffuse",
"stage3/rocks_ambient",
"stage3/rocks_normal",
"stage3/rocks_roughness",
"stage3/rocks_diffuse",
"stage3/leaves_ambient",
"stage3/leaves_normal",
"stage3/leaves_roughness",
"stage3/leaves_diffuse",
preload_resources(RES_TEXTURE, RESF_DEFAULT,
"stage3/spellbg1",
"stage3/spellbg2",
"stage3/wspellbg",
"stage3/wspellclouds",
"stage3/wspellswarm",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
preload_resources(RES_MATERIAL, RESF_DEFAULT,
"stage3/ground",
"stage3/leaves",
"stage3/rocks",
"stage3/trees",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
"stage3/ground",
"stage3/leaves",
"stage3/rocks",
"stage3/trees",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"zbuf_fog",

View file

@ -80,47 +80,81 @@ static bool stage4_water_composite(Framebuffer *reflections) {
return true;
}
static uint stage4_lake_pos(Stage3D *s3d, vec3 pos, float maxrange) {
vec3 p = {0, 0, 0};
return single3dpos(s3d, pos, maxrange, p);
}
static void stage4_lake_draw(vec3 pos) {
static void stage4_bg_setup_pbr_lighting_outdoors(Camera3D *cam) {
PointLight3D lights[] = {
{ { 0, 0, 0 }, { 3, 4, 5 } },
{ { 0, 25, 3 }, { 4, 20, 22 } },
};
vec3 r;
Camera3D *cam = &stage_3d_context.cam;
camera3d_unprojected_ray(cam, global.plr.pos, r);
glm_vec3_scale(r, 4, r);
glm_vec3_add(cam->pos, r, lights[0].pos);
r_mat_mv_push();
r_mat_mv_translate(pos[0], pos[1], pos[2]);
r_shader("pbr");
camera3d_set_point_light_uniforms(cam, ARRAY_SIZE(lights), lights);
}
static void stage4_bg_setup_pbr_env_outdoors(Camera3D *cam, PBREnvironment *env) {
stage4_bg_setup_pbr_lighting_outdoors(cam);
glm_vec3_broadcast(1.0f, env->ambient_color);
}
static void stage4_bg_setup_pbr_lighting_indoors(Camera3D *cam, vec3 pos) {
float xoff = 3.0f;
float zoff = 1.3f;
PointLight3D lights[] = {
{ { -xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } },
{ { -xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } },
{ { -xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } },
};
for(int i = 0; i < ARRAY_SIZE(lights); i++) {
float t = global.frames * 0.02f;
float mod1 = cosf(13095434.0f * lights[i].pos[1]);
float mod2 = sinf(1242435.0f * lights[i].pos[0] * lights[i].pos[1]);
float f = (
sinf((1.0f + mod1) * t) +
sinf((2.35f + mod2) * t + mod1) +
sinf((3.1257f + mod1 * mod2) * t + mod2)
) / 3.0f;
glm_vec3_scale(lights[i].radiance, 0.6f + 0.4f * f, lights[i].radiance);
}
camera3d_set_point_light_uniforms(cam, ARRAY_SIZE(lights), lights);
}
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage4/ground_diffuse");
r_uniform_sampler("roughness_map", "stage4/ground_roughness");
r_uniform_sampler("normal_map", "stage4/ground_normal");
r_uniform_sampler("ambient_map", "stage4/ground_ambient");
r_uniform_vec3("ambient_color", 1, 1, 1);
static void stage4_bg_setup_pbr_env_indoors(Camera3D *cam, vec3 pos, PBREnvironment *env) {
stage4_bg_setup_pbr_lighting_indoors(cam, pos);
glm_vec3_copy(&stage4_draw_data->ambient_color.r, env->ambient_color);
log_debug("%0.2f %0.2f %0.2f", env->ambient_color[0], env->ambient_color[1], env->ambient_color[2]);
}
r_draw_model("stage4/ground");
static uint stage4_lake_pos(Stage3D *s3d, vec3 pos, float maxrange) {
vec3 p = {0, 0, 0};
return single3dpos(s3d, pos, maxrange, p);
}
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage4/mansion_diffuse");
r_uniform_sampler("roughness_map", "stage4/mansion_roughness");
r_uniform_sampler("normal_map", "stage4/mansion_normal");
r_uniform_sampler("ambient_map", "stage4/mansion_ambient");
static void stage4_lake_draw(vec3 pos) {
r_state_push();
r_mat_mv_push();
r_mat_mv_translate_v(pos);
r_shader("pbr");
PBREnvironment env = { 0 };
stage4_bg_setup_pbr_env_outdoors(&stage_3d_context.cam, &env);
pbr_draw_model(&stage4_draw_data->models.ground, &env);
pbr_draw_model(&stage4_draw_data->models.mansion, &env);
r_draw_model("stage4/mansion");
r_mat_mv_pop();
r_shader_standard();
r_state_pop();
}
static uint stage4_corridor_pos(Stage3D *s3d, vec3 pos, float maxrange) {
@ -139,42 +173,19 @@ static uint stage4_corridor_pos(Stage3D *s3d, vec3 pos, float maxrange) {
}
static void stage4_corridor_draw(vec3 pos) {
real xoff = 3;
real zoff = 1.3;
PointLight3D lights[] = {
{ { -xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } },
{ { -xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } },
{ { -xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } },
};
for(int i = 0; i < ARRAY_SIZE(lights); i++) {
real t = global.frames*0.02;
real mod1 = cos(13095434*lights[i].pos[1]);
real mod2 = sin(1242435*lights[i].pos[0]*lights[i].pos[1]);
double f = (sin((1+mod1)*t) + sin((2.35+mod2)*t+mod1) + sin((3.1257+mod1*mod2)*t+mod2))/3;
glm_vec3_scale(lights[i].radiance,0.6+0.4*f, lights[i].radiance);
}
r_state_push();
r_mat_mv_push();
r_mat_mv_translate(pos[0], pos[1], pos[2]);
//r_mat_mv_rotate(pos[1]/2000, 0, 1, 0);
r_mat_mv_translate_v(pos);
r_shader("pbr");
camera3d_set_point_light_uniforms(&stage_3d_context.cam, ARRAY_SIZE(lights), lights);
PBREnvironment env = { 0 };
stage4_bg_setup_pbr_env_indoors(&stage_3d_context.cam, pos, &env);
r_uniform_float("metallic", 0);
r_uniform_sampler("tex", "stage4/corridor_diffuse");
r_uniform_sampler("roughness_map", "stage4/corridor_roughness");
r_uniform_sampler("normal_map", "stage4/corridor_normal");
r_uniform_sampler("ambient_map", "stage4/corridor_ambient");
r_uniform_vec3_rgb("ambient_color", &stage4_draw_data->ambient_color);
pbr_draw_model(&stage4_draw_data->models.corridor, &env);
r_draw_model("stage4/corridor");
r_mat_mv_pop();
r_state_pop();
}
void stage4_draw(void) {
@ -189,6 +200,10 @@ void stage4_draw(void) {
void stage4_drawsys_init(void) {
stage4_draw_data = calloc(1, sizeof(*stage4_draw_data));
stage3d_init(&stage_3d_context, 16);
pbr_load_model(&stage4_draw_data->models.corridor, "stage4/corridor", "stage4/corridor");
pbr_load_model(&stage4_draw_data->models.ground, "stage4/ground", "stage4/ground");
pbr_load_model(&stage4_draw_data->models.mansion, "stage4/mansion", "stage4/mansion");
}
void stage4_drawsys_shutdown(void) {

View file

@ -11,10 +11,17 @@
#include "stagedraw.h"
#include "color.h"
#include "stageutils.h"
typedef struct Stage4DrawData {
Color ambient_color;
vec3 midboss_light_pos;
struct {
PBRModel corridor;
PBRModel ground;
PBRModel mansion;
} models;
} Stage4DrawData;
void stage4_drawsys_init(void);

View file

@ -86,21 +86,9 @@ static void stage4_preload(void) {
portrait_preload_base_sprite("kurumi", NULL, RESF_DEFAULT);
portrait_preload_face_sprite("kurumi", "normal", RESF_DEFAULT);
preload_resources(RES_BGM, RESF_OPTIONAL, "stage4", "stage4boss", NULL);
preload_resources(RES_SPRITE, RESF_DEFAULT,
preload_resources(RES_TEXTURE, RESF_DEFAULT,
"stage4/kurumibg1",
"stage4/kurumibg2",
"stage4/ground_ambient",
"stage4/ground_diffuse",
"stage4/ground_roughness",
"stage4/ground_normal",
"stage4/mansion_ambient",
"stage4/mansion_diffuse",
"stage4/mansion_roughness",
"stage4/mansion_normal",
"stage4/corridor_ambient",
"stage4/corridor_diffuse",
"stage4/corridor_roughness",
"stage4/corridor_normal",
NULL);
preload_resources(RES_SPRITE, RESF_DEFAULT,
"stage6/scythe", // Stage 6 is intentional
@ -115,10 +103,15 @@ static void stage4_preload(void) {
preload_resources(RES_ANIM, RESF_DEFAULT,
"boss/kurumi",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
"stage4/mansion",
"stage4/ground",
preload_resources(RES_MATERIAL, RESF_DEFAULT,
"stage4/corridor",
"stage4/ground",
"stage4/mansion",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
"stage4/corridor",
"stage4/ground",
"stage4/mansion",
NULL);
preload_resources(RES_TEXTURE, RESF_OPTIONAL,
"part/sinewave",

View file

@ -10,6 +10,7 @@
#include "taisei.h"
#include "stagedraw.h"
#include "stageutils.h"
typedef struct Stage5DrawData {
@ -33,6 +34,11 @@ typedef struct Stage5DrawData {
float rad;
} stairs;
struct {
PBRModel metal;
PBRModel stairs;
PBRModel wall;
} models;
} Stage5DrawData;
void stage5_drawsys_init(void);

View file

@ -18,7 +18,6 @@ enum {
};
typedef struct Stage6DrawData {
struct {
float position[3*NUM_STARS];
} stars;
@ -32,6 +31,19 @@ typedef struct Stage6DrawData {
FBPair fbpair;
} baryon;
struct {
PBRModel rim;
PBRModel spires;
PBRModel stairs;
PBRModel tower;
PBRModel tower_bottom;
// these don't use pbr materials
Model *calabi_yau_quintic;
Model *top_plate;
} models;
Texture *envmap;
} Stage6DrawData;
Stage6DrawData* stage6_get_draw_data(void);

View file

@ -12,6 +12,8 @@
#include "global.h"
#include "util/glm.h"
#include "video.h"
#include "resource/model.h"
#include "resource/material.h"
Stage3D stage_3d_context;
@ -52,6 +54,19 @@ void stage3d_apply_transforms(Stage3D *s, mat4 mat) {
camera3d_apply_transforms(&s->cam, mat);
}
void camera3d_apply_inverse_transforms(Camera3D *cam, mat4 mat) {
// TODO optimize this
mat4 temp;
glm_mat4_identity(temp);
camera3d_apply_transforms(cam, temp);
glm_mat4_inv_fast(temp, mat);
}
void stage3d_apply_inverse_transforms(Stage3D *s, mat4 mat) {
camera3d_apply_inverse_transforms(&s->cam, mat);
}
// The author that brought you linear3dpos and that one function
// that calculates the closest point to a line segment proudly presents:
//
@ -121,6 +136,58 @@ void camera3d_set_point_light_uniforms(
r_uniform_int("light_count", num_lights);
}
void pbr_set_material_uniforms(const PBRMaterial *m, const PBREnvironment *env) {
int flags = 0;
if(m->diffuse_map) {
r_uniform_sampler("diffuse_map", m->diffuse_map);
flags |= PBR_FEATURE_DIFFUSE_MAP;
}
if(m->normal_map) {
r_uniform_sampler("normal_map", m->normal_map);
flags |= PBR_FEATURE_NORMAL_MAP;
}
if(m->roughness_map) {
r_uniform_sampler("roughness_map", m->roughness_map);
flags |= PBR_FEATURE_ROUGHNESS_MAP;
}
if(m->ambient_map) {
r_uniform_sampler("ambient_map", m->ambient_map);
flags |= PBR_FEATURE_AMBIENT_MAP;
}
if(env->environment_map) {
r_uniform_sampler("environment_map", env->environment_map);
r_uniform_mat4("inv_camera_transform", (vec4*)env->cam_inverse_transform);
flags |= PBR_FEATURE_ENVIRONMENT_MAP;
}
vec4 diffuseRGB_metallicA;
glm_vec3_copy((float*)m->diffuse_color, diffuseRGB_metallicA);
diffuseRGB_metallicA[3] = m->metallic_value;
r_uniform_vec4_vec("diffuseRGB_metallicA", diffuseRGB_metallicA);
vec4 ambientRGB_roughnessA;
glm_vec3_mul((float*)env->ambient_color, (float*)m->ambient_color, ambientRGB_roughnessA);
ambientRGB_roughnessA[3] = m->roughness_value;
r_uniform_vec4_vec("ambientRGB_roughnessA", ambientRGB_roughnessA);
r_uniform_int("features_mask", flags);
}
void pbr_draw_model(const PBRModel *pmdl, const PBREnvironment *env) {
pbr_set_material_uniforms(NOT_NULL(pmdl->mat), env);
r_draw_model_ptr(NOT_NULL(pmdl->mdl), 0, 0);
}