2020-08-11 12:07:21 -04:00
# include "shadercompiler.hpp"
# include <spirv_cpp.hpp>
# include <spirv_msl.hpp>
# include <SPIRV/GlslangToSpv.h>
# include "file.hpp"
# include "log.hpp"
# include "engine.hpp"
# include "string_utils.hpp"
# include "DirStackIncluder.h"
const TBuiltInResource DefaultTBuiltInResource = {
/* .MaxLights = */ 32 ,
/* .MaxClipPlanes = */ 6 ,
/* .MaxTextureUnits = */ 32 ,
/* .MaxTextureCoords = */ 32 ,
/* .MaxVertexAttribs = */ 64 ,
/* .MaxVertexUniformComponents = */ 4096 ,
/* .MaxVaryingFloats = */ 64 ,
/* .MaxVertexTextureImageUnits = */ 32 ,
/* .MaxCombinedTextureImageUnits = */ 80 ,
/* .MaxTextureImageUnits = */ 32 ,
/* .MaxFragmentUniformComponents = */ 4096 ,
/* .MaxDrawBuffers = */ 32 ,
/* .MaxVertexUniformVectors = */ 128 ,
/* .MaxVaryingVectors = */ 8 ,
/* .MaxFragmentUniformVectors = */ 16 ,
/* .MaxVertexOutputVectors = */ 16 ,
/* .MaxFragmentInputVectors = */ 15 ,
/* .MinProgramTexelOffset = */ - 8 ,
/* .MaxProgramTexelOffset = */ 7 ,
/* .MaxClipDistances = */ 8 ,
/* .MaxComputeWorkGroupCountX = */ 65535 ,
/* .MaxComputeWorkGroupCountY = */ 65535 ,
/* .MaxComputeWorkGroupCountZ = */ 65535 ,
/* .MaxComputeWorkGroupSizeX = */ 1024 ,
/* .MaxComputeWorkGroupSizeY = */ 1024 ,
/* .MaxComputeWorkGroupSizeZ = */ 64 ,
/* .MaxComputeUniformComponents = */ 1024 ,
/* .MaxComputeTextureImageUnits = */ 16 ,
/* .MaxComputeImageUniforms = */ 8 ,
/* .MaxComputeAtomicCounters = */ 8 ,
/* .MaxComputeAtomicCounterBuffers = */ 1 ,
/* .MaxVaryingComponents = */ 60 ,
/* .MaxVertexOutputComponents = */ 64 ,
/* .MaxGeometryInputComponents = */ 64 ,
/* .MaxGeometryOutputComponents = */ 128 ,
/* .MaxFragmentInputComponents = */ 128 ,
/* .MaxImageUnits = */ 8 ,
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8 ,
/* .MaxCombinedShaderOutputResources = */ 8 ,
/* .MaxImageSamples = */ 0 ,
/* .MaxVertexImageUniforms = */ 0 ,
/* .MaxTessControlImageUniforms = */ 0 ,
/* .MaxTessEvaluationImageUniforms = */ 0 ,
/* .MaxGeometryImageUniforms = */ 0 ,
/* .MaxFragmentImageUniforms = */ 8 ,
/* .MaxCombinedImageUniforms = */ 8 ,
/* .MaxGeometryTextureImageUnits = */ 16 ,
/* .MaxGeometryOutputVertices = */ 256 ,
/* .MaxGeometryTotalOutputComponents = */ 1024 ,
/* .MaxGeometryUniformComponents = */ 1024 ,
/* .MaxGeometryVaryingComponents = */ 64 ,
/* .MaxTessControlInputComponents = */ 128 ,
/* .MaxTessControlOutputComponents = */ 128 ,
/* .MaxTessControlTextureImageUnits = */ 16 ,
/* .MaxTessControlUniformComponents = */ 1024 ,
/* .MaxTessControlTotalOutputComponents = */ 4096 ,
/* .MaxTessEvaluationInputComponents = */ 128 ,
/* .MaxTessEvaluationOutputComponents = */ 128 ,
/* .MaxTessEvaluationTextureImageUnits = */ 16 ,
/* .MaxTessEvaluationUniformComponents = */ 1024 ,
/* .MaxTessPatchComponents = */ 120 ,
/* .MaxPatchVertices = */ 32 ,
/* .MaxTessGenLevel = */ 64 ,
/* .MaxViewports = */ 16 ,
/* .MaxVertexAtomicCounters = */ 0 ,
/* .MaxTessControlAtomicCounters = */ 0 ,
/* .MaxTessEvaluationAtomicCounters = */ 0 ,
/* .MaxGeometryAtomicCounters = */ 0 ,
/* .MaxFragmentAtomicCounters = */ 8 ,
/* .MaxCombinedAtomicCounters = */ 8 ,
/* .MaxAtomicCounterBindings = */ 1 ,
/* .MaxVertexAtomicCounterBuffers = */ 0 ,
/* .MaxTessControlAtomicCounterBuffers = */ 0 ,
/* .MaxTessEvaluationAtomicCounterBuffers = */ 0 ,
/* .MaxGeometryAtomicCounterBuffers = */ 0 ,
/* .MaxFragmentAtomicCounterBuffers = */ 1 ,
/* .MaxCombinedAtomicCounterBuffers = */ 1 ,
/* .MaxAtomicCounterBufferSize = */ 16384 ,
/* .MaxTransformFeedbackBuffers = */ 4 ,
/* .MaxTransformFeedbackInterleavedComponents = */ 64 ,
/* .MaxCullDistances = */ 8 ,
/* .MaxCombinedClipAndCullDistances = */ 8 ,
/* .MaxSamples = */ 4 ,
/* .maxMeshOutputVerticesNV = */ 256 ,
/* .maxMeshOutputPrimitivesNV = */ 512 ,
/* .maxMeshWorkGroupSizeX_NV = */ 32 ,
/* .maxMeshWorkGroupSizeY_NV = */ 1 ,
/* .maxMeshWorkGroupSizeZ_NV = */ 1 ,
/* .maxTaskWorkGroupSizeX_NV = */ 32 ,
/* .maxTaskWorkGroupSizeY_NV = */ 1 ,
/* .maxTaskWorkGroupSizeZ_NV = */ 1 ,
/* .maxMeshViewCountNV = */ 4 ,
2020-08-13 07:48:50 -04:00
/* .maxDualSourceDrawBuffersEXT = */ 4 ,
/* .limits = */ TLimits {
/* .nonInductiveForLoops = */ true ,
/* .whileLoops = */ true ,
/* .doWhileLoops = */ true ,
/* .generalUniformIndexing = */ true ,
/* .generalAttributeMatrixVectorIndexing = */ true ,
/* .generalVaryingIndexing = */ true ,
/* .generalSamplerIndexing = */ true ,
/* .generalVariableIndexing = */ true ,
/* .generalConstantMatrixVectorIndexing = */ true ,
} } ;
2020-08-11 12:07:21 -04:00
const std : : vector < unsigned int > CompileGLSL ( const std : : string & filename , EShLanguage ShaderType , bool skinned , bool cubemap ) {
std : : string newString = " #version 430 core \n " ;
newString + = " #extension GL_GOOGLE_include_directive : enable \n " ;
newString + = " #extension GL_GOOGLE_cpp_style_line_directive : enable \n " ;
if ( skinned )
newString + = " #define BONE \n " ;
if ( cubemap )
newString + = " #define CUBEMAP \n " ;
newString + = " #line 1 \n " ;
newString + = filename ;
const char * InputCString = newString . c_str ( ) ;
glslang : : TShader Shader ( ShaderType ) ;
Shader . setStrings ( & InputCString , 1 ) ;
int ClientInputSemanticsVersion = 100 ; // maps to, say, #define VULKAN 100
glslang : : EShTargetClientVersion VulkanClientVersion = glslang : : EShTargetVulkan_1_1 ;
glslang : : EShTargetLanguageVersion TargetVersion = glslang : : EShTargetSpv_1_0 ;
Shader . setEnvInput ( glslang : : EShSourceGlsl , ShaderType , glslang : : EShClientVulkan , ClientInputSemanticsVersion ) ;
Shader . setEnvClient ( glslang : : EShClientVulkan , VulkanClientVersion ) ;
Shader . setEnvTarget ( glslang : : EShTargetSpv , TargetVersion ) ;
TBuiltInResource Resources = DefaultTBuiltInResource ;
EShMessages messages = ( EShMessages ) ( EShMsgSpvRules ) ;
DirStackFileIncluder includer ;
2020-08-13 07:48:50 -04:00
includer . pushExternalLocalDirectory ( file : : get_domain_path ( file : : Domain : : Internal ) . string ( ) ) ;
2020-08-11 12:07:21 -04:00
if ( ! Shader . parse ( & Resources , 100 , false , ( EShMessages ) 0 , includer ) ) {
2020-08-14 20:53:22 -04:00
console : : error ( System : : Renderer , " {} " , Shader . getInfoLog ( ) ) ;
2020-08-11 12:07:21 -04:00
return { } ;
}
glslang : : TProgram Program ;
Program . addShader ( & Shader ) ;
if ( ! Program . link ( messages ) ) {
console : : error ( System : : None , " Failed to link shader: {} {} {} " , filename , Shader . getInfoLog ( ) , Shader . getInfoDebugLog ( ) ) ;
return { } ;
}
std : : vector < unsigned int > SpirV ;
spv : : SpvBuildLogger logger ;
glslang : : SpvOptions spvOptions ;
glslang : : GlslangToSpv ( * Program . getIntermediate ( ShaderType ) , SpirV , & logger , & spvOptions ) ;
return SpirV ;
}
2020-08-14 17:45:51 -04:00
std : : variant < std : : string , std : : vector < uint32_t > > get_shader ( std : : string filename , bool skinned , bool cubemap ) {
2020-08-11 12:07:21 -04:00
auto shader_file = file : : open ( file : : internal_domain / filename ) ;
2020-08-14 20:53:22 -04:00
if ( ! shader_file . has_value ( ) ) {
console : : error ( System : : Renderer , " Failed to open shader file {}! " , filename ) ;
2020-08-11 12:07:21 -04:00
return " " ;
}
EShLanguage lang ;
if ( filename . find ( " vert " ) ! = std : : string : : npos ) {
lang = EShLangVertex ;
} else {
lang = EShLangFragment ;
}
auto vertexSPIRV = CompileGLSL ( shader_file - > read_as_string ( ) , lang , skinned , cubemap ) ;
2020-08-14 17:45:51 -04:00
# ifdef PLATFORM_MACOS
2020-08-11 12:07:21 -04:00
spirv_cross : : CompilerMSL msl ( std : : move ( vertexSPIRV ) ) ;
2020-08-14 17:45:51 -04:00
2020-08-11 12:07:21 -04:00
spirv_cross : : CompilerMSL : : Options opts ;
opts . platform = spirv_cross : : CompilerMSL : : Options : : Platform : : macOS ;
opts . enable_decoration_binding = true ;
2020-08-14 17:45:51 -04:00
2020-08-11 12:07:21 -04:00
msl . set_msl_options ( opts ) ;
2020-08-14 17:45:51 -04:00
2020-08-11 12:07:21 -04:00
return msl . compile ( ) ;
2020-08-14 17:45:51 -04:00
# else
return vertexSPIRV ;
# endif
2020-08-11 12:07:21 -04:00
}
GFXPipeline * ShaderCompiler : : create_static_pipeline ( GFXGraphicsPipelineCreateInfo createInfo , bool positions_only , bool cubemap ) {
// take vertex src
std : : string vertex_path = createInfo . shaders . vertex_path . data ( ) ;
vertex_path + = " .glsl " ;
2020-08-14 17:45:51 -04:00
createInfo . shaders . vertex_src = get_shader ( vertex_path , false , cubemap ) ;
2020-08-11 12:07:21 -04:00
createInfo . shaders . vertex_path = " " ;
if ( positions_only ) {
createInfo . vertex_input . inputs = {
{ position_buffer_index , sizeof ( Vector3 ) }
} ;
createInfo . vertex_input . attributes = {
{ position_buffer_index , 0 , 0 , GFXVertexFormat : : FLOAT3 }
} ;
} else {
createInfo . vertex_input . inputs = {
{ position_buffer_index , sizeof ( Vector3 ) } ,
{ normal_buffer_index , sizeof ( Vector3 ) } ,
{ texcoord_buffer_index , sizeof ( Vector2 ) } ,
{ tangent_buffer_index , sizeof ( Vector3 ) } ,
{ bitangent_buffer_index , sizeof ( Vector3 ) }
} ;
createInfo . vertex_input . attributes = {
{ position_buffer_index , 0 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ normal_buffer_index , 1 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ texcoord_buffer_index , 2 , 0 , GFXVertexFormat : : FLOAT2 } ,
{ tangent_buffer_index , 3 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ bitangent_buffer_index , 4 , 0 , GFXVertexFormat : : FLOAT3 }
} ;
}
return engine - > get_gfx ( ) - > create_graphics_pipeline ( createInfo ) ;
}
GFXPipeline * ShaderCompiler : : create_skinned_pipeline ( GFXGraphicsPipelineCreateInfo createInfo , bool positions_only ) {
createInfo . label + = " (Skinned) " ;
// take vertex src
std : : string vertex_path = createInfo . shaders . vertex_path . data ( ) ;
vertex_path + = " .glsl " ;
2020-08-14 17:45:51 -04:00
createInfo . shaders . vertex_src = get_shader ( vertex_path , true , false ) ;
2020-08-11 12:07:21 -04:00
createInfo . shaders . vertex_path = " " ;
if ( positions_only ) {
createInfo . vertex_input . inputs = {
{ position_buffer_index , sizeof ( Vector3 ) } ,
{ bone_buffer_index , sizeof ( BoneVertexData ) }
} ;
createInfo . vertex_input . attributes = {
{ position_buffer_index , 0 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ bone_buffer_index , 4 , offsetof ( BoneVertexData , ids ) , GFXVertexFormat : : INT4 } ,
{ bone_buffer_index , 5 , offsetof ( BoneVertexData , weights ) , GFXVertexFormat : : FLOAT4 }
} ;
} else {
createInfo . vertex_input . inputs = {
{ position_buffer_index , sizeof ( Vector3 ) } ,
{ normal_buffer_index , sizeof ( Vector3 ) } ,
{ texcoord_buffer_index , sizeof ( Vector2 ) } ,
{ tangent_buffer_index , sizeof ( Vector3 ) } ,
{ bitangent_buffer_index , sizeof ( Vector3 ) } ,
{ bone_buffer_index , sizeof ( BoneVertexData ) }
} ;
createInfo . vertex_input . attributes = {
{ position_buffer_index , 0 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ normal_buffer_index , 1 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ texcoord_buffer_index , 2 , 0 , GFXVertexFormat : : FLOAT2 } ,
{ tangent_buffer_index , 3 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ bitangent_buffer_index , 4 , 0 , GFXVertexFormat : : FLOAT3 } ,
{ bone_buffer_index , 5 , offsetof ( BoneVertexData , ids ) , GFXVertexFormat : : INT4 } ,
{ bone_buffer_index , 6 , offsetof ( BoneVertexData , weights ) , GFXVertexFormat : : FLOAT4 } ,
} ;
}
return engine - > get_gfx ( ) - > create_graphics_pipeline ( createInfo ) ;
}
std : : tuple < GFXPipeline * , GFXPipeline * > ShaderCompiler : : create_pipeline_permutations ( GFXGraphicsPipelineCreateInfo & createInfo , bool positions_only ) {
glslang : : InitializeProcess ( ) ;
auto st = create_static_pipeline ( createInfo , positions_only ) ;
auto ss = create_skinned_pipeline ( createInfo , positions_only ) ;
return { st , ss } ;
}
std : : vector < MaterialNode * > walked_nodes ;
void walk_node ( std : : string & src , MaterialNode * node ) {
if ( utility : : contains ( walked_nodes , node ) )
return ;
walked_nodes . push_back ( node ) ;
for ( auto & input : node - > inputs ) {
if ( input . connected_node ! = nullptr )
walk_node ( src , input . connected_node ) ;
}
std : : string intermediate = node - > get_glsl ( ) ;
for ( auto & property : node - > properties ) {
intermediate = replace_substring ( intermediate , property . name , node - > get_property_value ( property ) ) ;
}
for ( auto & input : node - > inputs ) {
intermediate = replace_substring ( intermediate , input . name , node - > get_connector_value ( input ) ) ;
}
for ( auto & output : node - > outputs ) {
intermediate = replace_substring ( intermediate , output . name , node - > get_connector_variable_name ( output ) ) ;
}
src + = intermediate ;
}
constexpr std : : string_view struct_info =
" layout (constant_id = 0) const int max_materials = 25; \n \
layout ( constant_id = 1 ) const int max_lights = 25 ; \ n \
layout ( constant_id = 2 ) const int max_spot_lights = 4 ; \ n \
layout ( constant_id = 3 ) const int max_probes = 4 ; \ n \
struct Material { \ n \
vec4 color , info ; \ n \
} ; \ n \
struct Light { \ n \
vec4 positionType ; \ n \
vec4 directionPower ; \ n \
vec4 colorSize ; \ n \
vec4 shadowsEnable ; \ n \
} ; \ n \
struct Probe { \ n \
vec4 position , size ; \ n \
} ; \ n \
layout ( std430 , binding = 1 ) buffer readonly SceneInformation { \ n \
vec4 options ; \ n \
vec4 camPos ; \ n \
mat4 vp , lightSpace ; \ n \
mat4 spotLightSpaces [ max_spot_lights ] ; \ n \
Material materials [ max_materials ] ; \ n \
Light lights [ max_lights ] ; \ n \
Probe probes [ max_probes ] ; \ n \
int numLights ; \ n \
} scene ; \ n \
layout ( binding = 2 ) uniform texture2D sun_shadow ; \ n \
layout ( binding = 4 ) uniform sampler shadow_sampler ; \ n \
layout ( binding = 5 ) uniform samplerShadow pcf_sampler ; \ n \
layout ( binding = 6 ) uniform texture2DArray spot_shadow ; \ n \
layout ( push_constant , binding = 0 ) uniform PushConstant { \ n \
mat4 model ; \ n \
int materialOffset ; \ n \
} ; \ n " ;
2020-08-14 17:45:51 -04:00
std : : variant < std : : string , std : : vector < uint32_t > > ShaderCompiler : : compile_material_fragment ( Material & material , bool use_ibl ) {
2020-08-11 12:07:21 -04:00
walked_nodes . clear ( ) ;
if ( ! render_options . enable_ibl )
use_ibl = false ;
std : : string src ;
switch ( render_options . shadow_filter ) {
case ShadowFilter : : None :
src + = " #define SHADOW_FILTER_NONE \n " ;
break ;
case ShadowFilter : : PCF :
src + = " #define SHADOW_FILTER_PCF \n " ;
break ;
case ShadowFilter : : PCSS :
src + = " #define SHADOW_FILTER_PCSS \n " ;
break ;
}
src + = " layout (location = 0) in vec3 in_frag_pos; \n " ;
src + = " layout(location = 1) in vec3 in_normal; \n " ;
src + = " layout(location = 2) in vec2 in_uv; \n " ;
src + = " layout(location = 0) out vec4 frag_output; \n " ;
if ( render_options . enable_point_shadows ) {
src + = " #define POINT_SHADOWS_SUPPORTED \n " ;
src + = " layout (binding = 3) uniform textureCubeArray point_shadow; \n " ;
}
src + = struct_info ;
if ( use_ibl ) {
src + = " layout (binding = 7) uniform samplerCubeArray irrandianceSampler; \n \
layout ( binding = 8 ) uniform samplerCubeArray prefilterSampler ; \ n \
layout ( binding = 9 ) uniform sampler2D brdfSampler ; \ n " ;
}
src + = " layout(location = 4) in vec4 fragPosLightSpace; \n " ;
src + = " layout(location = 5) in mat3 in_tbn; \n " ;
src + = " layout(location = 14) in vec4 fragPostSpotLightSpace[max_spot_lights]; \n " ;
src + = " #include \" common.glsl \" \n " ;
src + = " #include \" rendering.glsl \" \n " ;
material . bound_textures . clear ( ) ;
// insert samplers as needed
int sampler_index = 10 ;
for ( auto & node : material . nodes ) {
for ( auto & property : node - > properties ) {
if ( property . type = = DataType : : AssetTexture ) {
material . bound_textures [ sampler_index ] = property . value_tex ;
src + = " layout(binding = " + std : : to_string ( sampler_index + + ) + " ) uniform sampler2D " + node - > get_property_variable_name ( property ) + " ; \n " ;
}
}
}
if ( use_ibl ) {
src + = " vec3 get_reflect(int i, vec3 final_normal) { \n \
const vec3 direction = normalize ( in_frag_pos - scene . camPos . xyz ) ; \ n \
const vec3 reflection = reflect ( direction , normalize ( final_normal ) ) ; \ n \
vec3 box_max = scene . probes [ i ] . position . xyz + ( scene . probes [ i ] . size . xyz / 2.0f ) ; \ n \
vec3 box_min = scene . probes [ i ] . position . xyz + - ( scene . probes [ i ] . size . xyz / 2.0f ) ; \ n \
vec3 unitary = vec3 ( 1.0 ) ; \ n \
vec3 first_plane_intersect = ( box_max - in_frag_pos ) / reflection ; \ n \
vec3 second_plane_intersect = ( box_min - in_frag_pos ) / reflection ; \ n \
vec3 furthest_plane = max ( first_plane_intersect , second_plane_intersect ) ; \ n \
float distance = min ( furthest_plane . x , min ( furthest_plane . y , furthest_plane . z ) ) ; \ n \
vec3 intersect_position_world = in_frag_pos + reflection * distance ; \ n \
return intersect_position_world - scene . probes [ i ] . position . xyz ; \ n } \ n " ;
}
if ( render_options . enable_normal_shadowing ) {
src + = " float calculate_normal_lighting(in sampler2D normal_map, const vec3 normal, const vec3 light_dir) { \n \
float height_scale = 0.8 ; \ n \
float sample_count = 100.0 ; \ n \
float inv_sample_count = 1.0 / sample_count ; \ n \
float hardness = 50 * 0.5 ; \ n \
float lighting = clamp ( dot ( light_dir , normal ) , 0.0 , 1.0 ) ; \ n \
float slope = - lighting ; \ n \
vec2 dir = light_dir . xy * vec2 ( 1.0 , - 1.0 ) * height_scale ; \ n \
float max_slope = 0.0 ; \ n \
float step = inv_sample_count ; \ n \
float pos = step ; \ n \
pos = ( - lighting > = 0.0 ) ? 1.001 : pos ; \ n \
vec2 noise = fract ( in_frag_pos . xy * 0.5 ) ; \ n \
noise . x = noise . x + noise . y * 0.5 ; \ n \
pos = step - step * noise . x ; \ n \
float shadow = 0.0 ; \ n \
while ( pos < = 1.0 ) { \ n \
vec3 tmp_normal = texture ( normal_map , in_uv + dir * pos ) . rgb ; \ n \
tmp_normal = in_tbn * ( tmp_normal * 2.0 - 1.0 ) ; \ n \
float tmp_lighting = dot ( light_dir , tmp_normal ) ; \ n \
float shadowed = - tmp_lighting ; \ n \
slope + = shadowed ; \ n \
if ( slope > max_slope ) { \ n \
shadow + = hardness * ( 1.0 - pos ) ; \ n \
} \ n \
max_slope = max ( max_slope , slope ) ; \ n \
pos + = step ; \ n \
} \ n \
return clamp ( 1.0 - shadow * inv_sample_count , 0.0 , 1.0 ) ; \ n \
} \ n " ;
}
src + = " void main() { \n " ;
bool has_output = false ;
bool has_normal_mapping = false ;
std : : string normal_map_property_name ;
for ( auto & node : material . nodes ) {
if ( ! strcmp ( node - > get_name ( ) , " Material Output " ) ) {
for ( auto & input : node - > inputs ) {
if ( input . is_normal_map & & input . connected_node ! = nullptr ) {
has_normal_mapping = true ;
normal_map_property_name = input . connected_node - > get_property_variable_name ( input . connected_node - > properties [ 0 ] ) ; // quick and dirty workaround to get the normal map texture name
}
}
walk_node ( src , node . get ( ) ) ;
has_output = true ;
}
}
if ( ! has_output ) {
src + = " vec3 final_diffuse_color = vec3(1); \n " ;
src + = " float final_roughness = 0.5; \n " ;
src + = " float final_metallic = 0.0; \n " ;
src + = " vec3 final_normal = in_normal; \n " ;
}
src + =
" ComputedSurfaceInfo surface_info = compute_surface(final_diffuse_color.rgb, final_normal, final_metallic, final_roughness); \n \
vec3 Lo = vec3 ( 0 ) ; \ n \
for ( int i = 0 ; i < scene . numLights ; i + + ) { \ n \
const int type = int ( scene . lights [ i ] . positionType . w ) ; \ n \
ComputedLightInformation light_info ; \ n \
switch ( type ) { \ n \
case 0 : \ n \
light_info = calculate_point ( scene . lights [ i ] ) ; \ n \
break ; \ n \
case 1 : \ n \
light_info = calculate_spot ( scene . lights [ i ] ) ; \ n \
break ; \ n \
case 2 : \ n \
light_info = calculate_sun ( scene . lights [ i ] ) ; \ n \
break ; \ n \
} \ n \
ComputedLightSurfaceInfo light_surface_info = compute_light_surface ( light_info . direction , surface_info ) ; \ n " ;
if ( render_options . enable_normal_mapping & & has_normal_mapping & & render_options . enable_normal_shadowing ) {
src + = std : : string ( " light_info.radiance *= calculate_normal_lighting( " ) + normal_map_property_name + " , final_normal, light_info.direction); \n " ;
}
src + = " Lo += (light_surface_info.kD * final_diffuse_color.rgb / PI + light_surface_info.specular) * light_surface_info.NdotL * scene.lights[i].colorSize.xyz * light_info.radiance; \n \
} \ n " ;
if ( use_ibl ) {
src + =
" const vec3 F = fresnel_schlick_roughness(surface_info.NdotV, surface_info.F0, surface_info.roughness); \n \
const vec3 kD = ( 1.0 - F ) * ( 1.0 - surface_info . metallic ) ; \ n \
vec3 ambient = vec3 ( 0.0 ) ; \
float sum = 0.0 ; \ n \
for ( int i = 0 ; i < max_probes ; i + + ) { \
if ( scene . probes [ i ] . position . w = = 1 ) { \ n \
vec3 position = scene . probes [ i ] . position . xyz ; \
vec3 probe_min = position - ( scene . probes [ i ] . size . xyz / 2.0 ) ; \
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 ) ) & & scene . probes [ i ] . position . w = = 1 ) { \
float intensity = 1.0 - length ( abs ( in_frag_pos - position ) / ( scene . probes [ i ] . size . xyz / 2.0 ) ) ; \ n \
intensity = clamp ( intensity , 0.0 , 1.0 ) * scene . probes [ i ] . size . w ; \ n \
const vec3 R = get_reflect ( i , surface_info . N ) ; \ n \
const vec2 brdf = texture ( brdfSampler , vec2 ( surface_info . NdotV , surface_info . roughness ) ) . rg ; \ n \
const vec3 sampledIrradiance = texture ( irrandianceSampler , vec4 ( surface_info . N , i ) ) . xyz ; \ n \
const vec3 prefilteredColor = textureLod ( prefilterSampler , vec4 ( R , i ) , surface_info . roughness * 4 ) . xyz ; \ n \
const vec3 diffuse = sampledIrradiance * final_diffuse_color . rgb ; \ n \
const vec3 specular = prefilteredColor * ( F * brdf . x + brdf . y ) ; \ n \
ambient + = ( kD * diffuse + specular ) * intensity ; \ n \
sum + = intensity ; \ n \
} \
} else if ( scene . probes [ i ] . position . w = = 2 ) { \ n \
const vec3 R = reflect ( - surface_info . V , surface_info . N ) ; \ n \
const vec2 brdf = texture ( brdfSampler , vec2 ( surface_info . NdotV , surface_info . roughness ) ) . rg ; \ n \
const vec3 sampledIrradiance = texture ( irrandianceSampler , vec4 ( surface_info . N , i ) ) . xyz ; \ n \
const vec3 prefilteredColor = textureLod ( prefilterSampler , vec4 ( R , i ) , surface_info . roughness * 4 ) . xyz ; \ n \
const vec3 diffuse = sampledIrradiance * final_diffuse_color . rgb ; \ n \
const vec3 specular = prefilteredColor * ( F * brdf . x + brdf . y ) ; \ n \
ambient + = ( kD * diffuse + specular ) * scene . probes [ i ] . size . w ; \ n \
sum + = 1.0 ; \ n \
} \ n \
} \ n \
ambient / = sum ; \ n " ;
src + = " frag_output = vec4(ambient + Lo, 1.0); \n " ;
} else {
src + = " frag_output = vec4(Lo, 1.0); \n " ;
}
src + = " } \n " ;
auto vertexSPIRV = CompileGLSL ( src , EShLangFragment , false , false ) ;
2020-08-14 17:45:51 -04:00
# ifdef PLATFORM_MACOS
2020-08-11 12:07:21 -04:00
spirv_cross : : CompilerMSL msl ( std : : move ( vertexSPIRV ) ) ;
2020-08-14 17:45:51 -04:00
2020-08-11 12:07:21 -04:00
spirv_cross : : CompilerMSL : : Options opts ;
opts . platform = spirv_cross : : CompilerMSL : : Options : : Platform : : macOS ;
opts . enable_decoration_binding = true ;
2020-08-14 17:45:51 -04:00
2020-08-11 12:07:21 -04:00
msl . set_msl_options ( opts ) ;
2020-08-14 17:45:51 -04:00
2020-08-11 12:07:21 -04:00
return msl . compile ( ) ;
2020-08-14 17:45:51 -04:00
# else
return vertexSPIRV ;
# endif
2020-08-11 12:07:21 -04:00
}