Archived
1
Fork 0

Use fmt::memory_buffer in material compiler

This commit is contained in:
Joshua Goins 2022-02-21 13:20:55 -05:00
parent 5401188196
commit 7b67ed73d8

View file

@ -33,14 +33,13 @@ ShaderSource get_shader(const std::string& filename, bool skinned, bool cubemap)
GFXPipeline* MaterialCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) { GFXPipeline* MaterialCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) {
// take vertex src // take vertex src
std::string vertex_path = createInfo.shaders.vertex_src.as_path().string(); const std::string vertex_path = fmt::format("{}.glsl", createInfo.shaders.vertex_src.as_path().string(););
vertex_path += ".glsl";
if (positions_only) if (positions_only)
createInfo.label += "shadow ver"; createInfo.label += " (shadow)";
if (cubemap) if (cubemap)
createInfo.label += "cubemap ver"; createInfo.label += " (cubemap)";
createInfo.shaders.vertex_src = get_shader(vertex_path, false, cubemap); createInfo.shaders.vertex_src = get_shader(vertex_path, false, cubemap);
@ -74,11 +73,10 @@ GFXPipeline* MaterialCompiler::create_static_pipeline(GFXGraphicsPipelineCreateI
} }
GFXPipeline* MaterialCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only) { GFXPipeline* MaterialCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only) {
createInfo.label += " (Skinned)"; createInfo.label += " (skinned)";
// take vertex src // take vertex src
std::string vertex_path = createInfo.shaders.vertex_src.as_path().string(); const std::string vertex_path = fmt::format("{}.glsl", createInfo.shaders.vertex_src.as_path().string());
vertex_path += ".glsl";
createInfo.shaders.vertex_src = get_shader(vertex_path, true, false); createInfo.shaders.vertex_src = get_shader(vertex_path, true, false);
@ -127,82 +125,89 @@ std::tuple<GFXPipeline*, GFXPipeline*> MaterialCompiler::create_pipeline_permuta
} }
constexpr std::string_view struct_info = constexpr std::string_view struct_info =
"layout (constant_id = 0) const int max_materials = 25;\n \ R"(layout (constant_id = 0) const int max_materials = 25;
layout (constant_id = 1) const int max_lights = 25;\n \ layout (constant_id = 1) const int max_lights = 25;
layout (constant_id = 2) const int max_spot_lights = 4;\n \ layout (constant_id = 2) const int max_spot_lights = 4;
layout (constant_id = 3) const int max_probes = 4;\n \ layout (constant_id = 3) const int max_probes = 4;
struct Material {\n \ struct Material {{
vec4 color, info;\n \ vec4 color, info;
};\n \ }};
struct Light {\n \ struct Light {{
vec4 positionType;\n \ vec4 positionType;
vec4 directionPower;\n \ vec4 directionPower;
vec4 colorSize;\n \ vec4 colorSize;
vec4 shadowsEnable;\n \ vec4 shadowsEnable;
};\n \ }};
struct Probe {\n \ struct Probe {{
vec4 position, size;\n \ vec4 position, size;
};\n \ }};
layout(std430, binding = 1) buffer readonly SceneInformation {\n \ layout(std430, binding = 1) buffer readonly SceneInformation {{
vec4 options;\n \ vec4 options;
vec4 camPos;\n \ vec4 camPos;
mat4 vp, lightSpace;\n \ mat4 vp, lightSpace;
mat4 spotLightSpaces[max_spot_lights];\n \ mat4 spotLightSpaces[max_spot_lights];
Material materials[max_materials];\n \ Material materials[max_materials];
Light lights[max_lights];\n \ Light lights[max_lights];
Probe probes[max_probes];\n \ Probe probes[max_probes];
int numLights;\n \ int numLights;
} scene;\n \ }} scene;
layout (binding = 2) uniform sampler2D sun_shadow;\n \ layout (binding = 2) uniform sampler2D sun_shadow;
layout (binding = 6) uniform sampler2DArray spot_shadow;\n \ layout (binding = 6) uniform sampler2DArray spot_shadow;
layout(push_constant) uniform PushConstant {\n \ layout(push_constant) uniform PushConstant {{
mat4 model;\n \ mat4 model;
};\n"; }};
)";
ShaderSource MaterialCompiler::compile_material_fragment(Material& material, bool use_ibl) { ShaderSource MaterialCompiler::compile_material_fragment(Material& material, bool use_ibl) {
if(!render_options.enable_ibl) if(!render_options.enable_ibl)
use_ibl = false; use_ibl = false;
std::string src; auto src = fmt::memory_buffer();
switch(render_options.shadow_filter) { switch(render_options.shadow_filter) {
case ShadowFilter::None: case ShadowFilter::None:
src += "#define SHADOW_FILTER_NONE\n"; format_to(std::back_inserter(src), "#define SHADOW_FILTER_NONE\n");
break; break;
case ShadowFilter::PCF: case ShadowFilter::PCF:
src += "#define SHADOW_FILTER_PCF\n"; format_to(std::back_inserter(src), "#define SHADOW_FILTER_PCF\n");
break; break;
case ShadowFilter::PCSS: case ShadowFilter::PCSS:
src += "#define SHADOW_FILTER_PCSS\n"; format_to(std::back_inserter(src), "#define SHADOW_FILTER_PCSS\n");
break; break;
} }
src += "layout (location = 0) in vec3 in_frag_pos;\n"; format_to(std::back_inserter(src),
src += "layout(location = 1) in vec3 in_normal;\n"; R"(layout (location = 0) in vec3 in_frag_pos;
src += "layout(location = 2) in vec2 in_uv;\n"; layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec2 in_uv;
src += "layout(location = 0) out vec4 frag_output;\n"; layout(location = 0) out vec4 frag_output;
)");
if(render_options.enable_point_shadows) { if(render_options.enable_point_shadows) {
src += "#define POINT_SHADOWS_SUPPORTED\n"; format_to(std::back_inserter(src),
src += "layout (binding = 3) uniform samplerCubeArray point_shadow;\n"; R"(#define POINT_SHADOWS_SUPPORTED
layout (binding = 3) uniform samplerCubeArray point_shadow;
)");
} }
src += struct_info; format_to(std::back_inserter(src), struct_info);
if(use_ibl) { if(use_ibl) {
src += "layout (binding = 7) uniform samplerCubeArray irrandianceSampler;\n \ format_to(std::back_inserter(src),
layout (binding = 8) uniform samplerCubeArray prefilterSampler;\n \ R"(layout (binding = 7) uniform samplerCubeArray irrandianceSampler;
layout (binding = 9) uniform sampler2D brdfSampler;\n"; layout (binding = 8) uniform samplerCubeArray prefilterSampler;
layout (binding = 9) uniform sampler2D brdfSampler;
)");
} }
src += "layout(location = 4) in vec4 fragPosLightSpace;\n"; format_to(std::back_inserter(src),
src += "layout(location = 5) in mat3 in_tbn;\n"; R"(layout(location = 4) in vec4 fragPosLightSpace;
src += "layout(location = 14) in vec4 fragPostSpotLightSpace[max_spot_lights];\n"; layout(location = 5) in mat3 in_tbn;
src += "layout(location = 13) in flat int inMaterialIndex;\n"; layout(location = 14) in vec4 fragPostSpotLightSpace[max_spot_lights];
layout(location = 13) in flat int inMaterialIndex;
src += "#include \"common.glsl\"\n"; #include "common.glsl"
src += "#include \"rendering.glsl\"\n"; #include "rendering.glsl"
)");
material.bound_textures.clear(); material.bound_textures.clear();
@ -211,156 +216,167 @@ ShaderSource MaterialCompiler::compile_material_fragment(Material& material, boo
if(material.colorProperty.type == DataType::AssetTexture) { if(material.colorProperty.type == DataType::AssetTexture) {
material.bound_textures[sampler_index] = material.colorProperty.value_tex; material.bound_textures[sampler_index] = material.colorProperty.value_tex;
src += "layout(binding = " + std::to_string(sampler_index++) + ") uniform sampler2D colorTexture;\n"; format_to(std::back_inserter(src), "layout(binding = {}) uniform sampler2D colorTexture;\n", sampler_index++);
} }
if(material.normalProperty.type == DataType::AssetTexture) { if(material.normalProperty.type == DataType::AssetTexture) {
material.bound_textures[sampler_index] = material.normalProperty.value_tex; material.bound_textures[sampler_index] = material.normalProperty.value_tex;
src += "layout(binding = " + std::to_string(sampler_index++) + ") uniform sampler2D normalTexture;\n"; format_to(std::back_inserter(src), "layout(binding = {}) uniform sampler2D normalTexture;\n", sampler_index++);
} }
if(use_ibl) { if(use_ibl) {
src += "vec3 get_reflect(int i, vec3 final_normal) {\n \ format_to(std::back_inserter(src),
const vec3 direction = normalize(in_frag_pos - scene.camPos.xyz);\n \ R"(vec3 get_reflect(int i, vec3 final_normal) {{
const vec3 reflection = reflect(direction, normalize(final_normal));\n \ const vec3 direction = normalize(in_frag_pos - scene.camPos.xyz);
vec3 box_max = scene.probes[i].position.xyz + (scene.probes[i].size.xyz / 2.0f);\n \ const vec3 reflection = reflect(direction, normalize(final_normal));
vec3 box_min = scene.probes[i].position.xyz + -(scene.probes[i].size.xyz / 2.0f);\n \ vec3 box_max = scene.probes[i].position.xyz + (scene.probes[i].size.xyz / 2.0f);
vec3 unitary = vec3(1.0);\n \ vec3 box_min = scene.probes[i].position.xyz + -(scene.probes[i].size.xyz / 2.0f);
vec3 first_plane_intersect = (box_max - in_frag_pos) / reflection;\n \ vec3 unitary = vec3(1.0);
vec3 second_plane_intersect = (box_min - in_frag_pos) / reflection;\n \ vec3 first_plane_intersect = (box_max - in_frag_pos) / reflection;
vec3 furthest_plane = max(first_plane_intersect, second_plane_intersect);\n \ vec3 second_plane_intersect = (box_min - in_frag_pos) / reflection;
float distance = min(furthest_plane.x, min(furthest_plane.y, furthest_plane.z));\n \ vec3 furthest_plane = max(first_plane_intersect, second_plane_intersect);
vec3 intersect_position_world = in_frag_pos + reflection * distance; \n \ float distance = min(furthest_plane.x, min(furthest_plane.y, furthest_plane.z));
return intersect_position_world - scene.probes[i].position.xyz;\n}\n"; vec3 intersect_position_world = in_frag_pos + reflection * distance;
return intersect_position_world - scene.probes[i].position.xyz;
}}
)");
} }
if(render_options.enable_normal_shadowing) { if(render_options.enable_normal_shadowing) {
src += "float calculate_normal_lighting(in sampler2D normal_map, const vec3 normal, const vec3 light_dir) {\n \ format_to(std::back_inserter(src),
float height_scale = 0.8;\n \ R"(float calculate_normal_lighting(in sampler2D normal_map, const vec3 normal, const vec3 light_dir) {{
float sample_count = 100.0;\n \ float height_scale = 0.8;
float inv_sample_count = 1.0 / sample_count;\n \ float sample_count = 100.0;
float hardness = 50 * 0.5;\n \ float inv_sample_count = 1.0 / sample_count;
float lighting = clamp(dot(light_dir, normal), 0.0, 1.0);\n \ float hardness = 50 * 0.5;
float slope = -lighting;\n \ float lighting = clamp(dot(light_dir, normal), 0.0, 1.0);
vec2 dir = light_dir.xy * vec2(1.0, -1.0) * height_scale;\n \ float slope = -lighting;
float max_slope = 0.0;\n \ vec2 dir = light_dir.xy * vec2(1.0, -1.0) * height_scale;
float step = inv_sample_count;\n \ float max_slope = 0.0;
float pos = step;\n \ float step = inv_sample_count;
pos = (-lighting >= 0.0) ? 1.001 : pos;\n \ float pos = step;
vec2 noise = fract(in_frag_pos.xy * 0.5);\n \ pos = (-lighting >= 0.0) ? 1.001 : pos;
noise.x = noise.x + noise.y * 0.5;\n \ vec2 noise = fract(in_frag_pos.xy * 0.5);
pos = step - step * noise.x;\n \ noise.x = noise.x + noise.y * 0.5;
float shadow = 0.0;\n \ pos = step - step * noise.x;
while(pos <= 1.0) {\n \ float shadow = 0.0;
vec3 tmp_normal = texture(normal_map, in_uv + dir * pos).rgb;\n \ while(pos <= 1.0) {{
tmp_normal = in_tbn * (tmp_normal * 2.0 - 1.0);\n \ vec3 tmp_normal = texture(normal_map, in_uv + dir * pos).rgb;
float tmp_lighting = dot(light_dir, tmp_normal);\n \ tmp_normal = in_tbn * (tmp_normal * 2.0 - 1.0);
float shadowed = -tmp_lighting;\n \ float tmp_lighting = dot(light_dir, tmp_normal);
slope += shadowed;\n \ float shadowed = -tmp_lighting;
if(slope > max_slope) {\n \ slope += shadowed;
shadow += hardness * (1.0 - pos);\n \ if(slope > max_slope) {{
}\n \ shadow += hardness * (1.0 - pos);
max_slope = max(max_slope, slope);\n \ }}
pos += step;\n \ max_slope = max(max_slope, slope);
}\n \ pos += step;
return clamp(1.0 - shadow * inv_sample_count, 0.0, 1.0);\n \ }}
}\n"; return clamp(1.0 - shadow * inv_sample_count, 0.0, 1.0);
}}
)");
} }
if(use_ibl) { if(use_ibl) {
src += "vec3 ibl(const int probe, const ComputedSurfaceInfo surface_info, const float intensity) {\n \ format_to(std::back_inserter(src),
const vec3 F = fresnel_schlick_roughness(surface_info.NdotV, surface_info.F0, surface_info.roughness);\n \ R"(vec3 ibl(const int probe, const ComputedSurfaceInfo surface_info, const float intensity) {{
const vec3 R = get_reflect(probe, surface_info.N);\n \ const vec3 F = fresnel_schlick_roughness(surface_info.NdotV, surface_info.F0, surface_info.roughness);
const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \ const vec3 R = get_reflect(probe, surface_info.N);
const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, probe)).xyz;\n \ const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg;
const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, probe), surface_info.roughness * 4).xyz;\n \ const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, probe)).xyz;
const vec3 diffuse = sampledIrradiance * surface_info.diffuse_color;\n \ const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, probe), surface_info.roughness * 4).xyz;
const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);\n \ const vec3 diffuse = sampledIrradiance * surface_info.diffuse_color;
return (diffuse + specular) * intensity;\n \ const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);
}\n"; return (diffuse + specular) * intensity;
}}
)");
} }
src += "void main() {\n"; format_to(std::back_inserter(src), "void main() {{\n");
if(material.colorProperty.type == DataType::Vector3) { if(material.colorProperty.type == DataType::Vector3) {
src += "vec3 Color = vec3(" + std::to_string(material.colorProperty.value.x) + "," format_to(std::back_inserter(src), "vec3 Color = vec3({}, {}, {});\n", material.colorProperty.value.x, material.colorProperty.value.y, material.colorProperty.value.z);
+ std::to_string(material.colorProperty.value.y) + ","
+ std::to_string(material.colorProperty.value.z) + ");\n";
} else if(material.colorProperty.type == DataType::AssetTexture) { } else if(material.colorProperty.type == DataType::AssetTexture) {
src += "vec3 Color = texture(colorTexture, in_uv).rgb;\n"; format_to(std::back_inserter(src), "vec3 Color = texture(colorTexture, in_uv).rgb;\n");
} else if(material.colorProperty.type == DataType::Float) { } else if(material.colorProperty.type == DataType::Float) {
src += "vec3 Color = vec3(" + std::to_string(material.colorProperty.float_value) + ");\n"; format_to(std::back_inserter(src),"vec3 Color = vec3({}});\n", material.colorProperty.float_value);
} }
src += "vec3 final_diffuse_color = from_srgb_to_linear(Color);\n"; format_to(std::back_inserter(src),
src += "float final_roughness = scene.materials[inMaterialIndex].info.y;\n"; R"(vec3 final_diffuse_color = from_srgb_to_linear(Color);
src += "float final_metallic = scene.materials[inMaterialIndex].info.x;\n"; float final_roughness = scene.materials[inMaterialIndex].info.y;
float final_metallic = scene.materials[inMaterialIndex].info.x;
)");
if(material.normalProperty.type == DataType::AssetTexture) { if(material.normalProperty.type == DataType::AssetTexture) {
prism::log("enabling normal mapping on material.."); prism::log("enabling normal mapping on material..");
src += "vec3 final_normal = texture(normalTexture, in_uv).rgb;\n"; format_to(std::back_inserter(src),
src += "final_normal = final_normal * 2.0 - 1.0;\n"; R"(vec3 final_normal = texture(normalTexture, in_uv).rgb;
src += "final_normal = in_tbn * final_normal;\n"; final_normal = final_normal * 2.0 - 1.0;
final_normal = in_tbn * final_normal;
)");
} else { } else {
src += "vec3 final_normal = in_normal;\n"; format_to(std::back_inserter(src), "vec3 final_normal = in_normal;\n");
} }
src += format_to(std::back_inserter(src),
"ComputedSurfaceInfo surface_info = compute_surface(final_diffuse_color.rgb, final_normal, final_metallic, final_roughness);\n \ R"(ComputedSurfaceInfo surface_info = compute_surface(final_diffuse_color.rgb, final_normal, final_metallic, final_roughness);
vec3 Lo = vec3(0);\n \ vec3 Lo = vec3(0);
for(int i = 0; i < scene.numLights; i++) {\n \ for(int i = 0; i < scene.numLights; i++) {{
const int type = int(scene.lights[i].positionType.w);\n \ const int type = int(scene.lights[i].positionType.w);
ComputedLightInformation light_info;\n \ ComputedLightInformation light_info;
switch(type) {\n \ switch(type) {{
case 0:\n \ case 0:
light_info = calculate_point(scene.lights[i]);\n \ light_info = calculate_point(scene.lights[i]);
break;\n \ break;
case 1:\n \ case 1:
light_info = calculate_spot(scene.lights[i]);\n \ light_info = calculate_spot(scene.lights[i]);
break;\n \ break;
case 2:\n \ case 2:
light_info = calculate_sun(scene.lights[i]);\n \ light_info = calculate_sun(scene.lights[i]);
break;\n \ break;
}\n \ }}
SurfaceBRDF surface_brdf = brdf(light_info.direction, surface_info);\n"; SurfaceBRDF surface_brdf = brdf(light_info.direction, surface_info);
)");
if(render_options.enable_normal_mapping && material.normalProperty.type == DataType::AssetTexture && render_options.enable_normal_shadowing) { if(render_options.enable_normal_mapping && material.normalProperty.type == DataType::AssetTexture && render_options.enable_normal_shadowing) {
src += std::string("light_info.radiance *= calculate_normal_lighting(normalTexture, final_normal, light_info.direction);\n"); format_to(std::back_inserter(src), "light_info.radiance *= calculate_normal_lighting(normalTexture, final_normal, light_info.direction);\n");
} }
src += "Lo += ((surface_brdf.specular + surface_brdf.diffuse) * light_info.radiance * surface_brdf.NdotL) * scene.lights[i].colorSize.rgb;\n \ format_to(std::back_inserter(src), "Lo += ((surface_brdf.specular + surface_brdf.diffuse) * light_info.radiance * surface_brdf.NdotL) * scene.lights[i].colorSize.rgb;\n \
}\n"; }}\n");
if(use_ibl) { if(use_ibl) {
src += format_to(std::back_inserter(src),
"vec3 ambient = vec3(0.0); \ R"(vec3 ambient = vec3(0.0);
float sum = 0.0;\n \ float sum = 0.0;
for(int i = 0; i < max_probes; i++) { \ for(int i = 0; i < max_probes; i++) {{
if(scene.probes[i].position.w == 1) {\n \ if(scene.probes[i].position.w == 1) {{
const vec3 position = scene.probes[i].position.xyz; \ const vec3 position = scene.probes[i].position.xyz;
const vec3 probe_min = position - (scene.probes[i].size.xyz / 2.0); \ const vec3 probe_min = position - (scene.probes[i].size.xyz / 2.0);
const vec3 probe_max = position + (scene.probes[i].size.xyz / 2.0); \ const vec3 probe_max = position + (scene.probes[i].size.xyz / 2.0);
if(all(greaterThan(in_frag_pos, probe_min)) && all(lessThan(in_frag_pos, probe_max))) { \ if(all(greaterThan(in_frag_pos, probe_min)) && all(lessThan(in_frag_pos, probe_max))) {{
float intensity = 1.0 - length(abs(in_frag_pos - position) / (scene.probes[i].size.xyz / 2.0));\n \ float intensity = 1.0 - length(abs(in_frag_pos - position) / (scene.probes[i].size.xyz / 2.0));
intensity = clamp(intensity, 0.0, 1.0) * scene.probes[i].size.w;\n \ intensity = clamp(intensity, 0.0, 1.0) * scene.probes[i].size.w;
ambient += ibl(i, surface_info, intensity);\n \ ambient += ibl(i, surface_info, intensity);
sum += intensity; \n \ sum += intensity;
} \ }}
} else if(scene.probes[i].position.w == 2) {\n \ }} else if(scene.probes[i].position.w == 2) {{
ambient += ibl(i, surface_info, scene.probes[i].size.w);\n \ ambient += ibl(i, surface_info, scene.probes[i].size.w);
sum += scene.probes[i].size.w; \n \ sum += scene.probes[i].size.w;
}\n \ }}
}\n \ }}
ambient /= sum;\n"; ambient /= sum;
)");
src += "frag_output = vec4(ambient + Lo, 1.0);\n"; format_to(std::back_inserter(src), "frag_output = vec4(ambient + Lo, 1.0);\n");
} else { } else {
src += "frag_output = vec4(Lo, 1.0);\n"; format_to(std::back_inserter(src), "frag_output = vec4(Lo, 1.0);\n");
} }
src += "}\n"; format_to(std::back_inserter(src), "}}\n");
return *shader_compiler.compile(ShaderLanguage::GLSL, ShaderStage::Fragment, ShaderSource(src), engine->get_gfx()->accepted_shader_language()); return *shader_compiler.compile(ShaderLanguage::GLSL, ShaderStage::Fragment, ShaderSource(to_string(src)), engine->get_gfx()->accepted_shader_language());
} }