-
-
Notifications
You must be signed in to change notification settings - Fork 23.7k
Description
Tested versions
-Reproducible in: 4.5.1.stable
System information
Godot v4.5.1.stable - macOS Sequoia (15.7.1) - Multi-window, 3 monitors - Metal (Mobile) - integrated Apple M2 Ultra (Apple8) - Apple M2 Ultra (24 threads) - 64.00 GiB memory
Issue description
It appears the generated native shader code for a completely unlit "unshaded" shader is still rather bloated with a ton of unused uniforms, vertex attributes and completely unnecessary dynamic branching. Both vertex and fragment. At least on Metal, not checked other APIs.
E.g. this is my very basic "everything-off" test shader:
shader_type spatial;
render_mode unshaded, shadows_disabled, ambient_light_disabled, fog_disabled, specular_disabled;
void fragment() {
ALBEDO = vec3(1.0, 0.0, 0.0);
}
It doesn't use any lighting, shadows, decals, fog etc. It is not intended for multi-mesh nor for multi-instancing. Just the simplest of simple unlit shader for best possible performance on a single MeshInstance3D node mesh.
It is not immediately obvious what is going on in the auto-generated native shader code. If you do "Inspect Native Shader Code" in shader editor it will come up with 35 or so variants all heavily peppered with conditional compiling based on macro defines. But if you check what's actually running on the GPU in Metal debugger it becomes clear there is a big room for optimisation. Especially a lot of dynamic branching, even in fragment shader ...
I can't seem to find any other shader type I can use for my unlit 3D shader other than "spacial". However the amount of unneeded GPU overhead it adds in is a bit staggering. This is what is what is being produced for the super simplistic "everything-off" unshaded gdshader listed above.
Vertex:
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
// Returns the determinant of a 2x2 matrix.
static inline __attribute__((always_inline))
float spvDet2x2(float a1, float a2, float b1, float b2)
{
return a1 * b2 - b1 * a2;
}
// Returns the inverse of a matrix, by using the algorithm of calculating the classical
// adjoint and dividing by the determinant. The contents of the matrix are changed.
static inline __attribute__((always_inline))
float3x3 spvInverse3x3(float3x3 m)
{
float3x3 adj; // The adjoint matrix (inverse after dividing by determinant)
// Create the transpose of the cofactors, as the classical adjoint of the matrix.
adj[0][0] = spvDet2x2(m[1][1], m[1][2], m[2][1], m[2][2]);
adj[0][1] = -spvDet2x2(m[0][1], m[0][2], m[2][1], m[2][2]);
adj[0][2] = spvDet2x2(m[0][1], m[0][2], m[1][1], m[1][2]);
adj[1][0] = -spvDet2x2(m[1][0], m[1][2], m[2][0], m[2][2]);
adj[1][1] = spvDet2x2(m[0][0], m[0][2], m[2][0], m[2][2]);
adj[1][2] = -spvDet2x2(m[0][0], m[0][2], m[1][0], m[1][2]);
adj[2][0] = spvDet2x2(m[1][0], m[1][1], m[2][0], m[2][1]);
adj[2][1] = -spvDet2x2(m[0][0], m[0][1], m[2][0], m[2][1]);
adj[2][2] = spvDet2x2(m[0][0], m[0][1], m[1][0], m[1][1]);
// Calculate the determinant as a combination of the cofactors of the first row.
float det = (adj[0][0] * m[0][0]) + (adj[0][1] * m[1][0]) + (adj[0][2] * m[2][0]);
// Divide the classical adjoint matrix by the determinant.
// If determinant is zero, matrix is not invertable, so leave it unchanged.
return (det != 0.0f) ? (adj * (1.0f / det)) : m;
}
constant uint pso_sc_packed_0_tmp [[function_constant(0)]];
constant uint pso_sc_packed_0 = is_function_constant_defined(pso_sc_packed_0_tmp) ? pso_sc_packed_0_tmp : 0u;
struct InstanceData
{
float4x4 transform;
float4x4 prev_transform;
uint flags;
uint instance_uniforms_ofs;
uint gi_offset;
uint layer_mask;
float4 lightmap_uv_scale;
uint2 reflection_probes;
uint2 omni_lights;
uint2 spot_lights;
uint2 decals;
float4 compressed_aabb_position_pad;
float4 compressed_aabb_size_pad;
float4 uv_scale;
};
struct InstanceDataBuffer
{
InstanceData data[1];
};
struct Transforms
{
float4 data[1];
};
struct DrawCall
{
uint uv_offset;
uint instance_index;
uint multimesh_motion_vectors_current_offset;
uint multimesh_motion_vectors_previous_offset;
};
struct SceneData
{
float4x4 projection_matrix;
float4x4 inv_projection_matrix;
float4x4 inv_view_matrix;
float4x4 view_matrix;
float4x4 projection_matrix_view[2];
float4x4 inv_projection_matrix_view[2];
float4 eye_offset[2];
float4x4 main_cam_inv_view_matrix;
float2 viewport_size;
float2 screen_pixel_size;
float4 directional_penumbra_shadow_kernel[32];
float4 directional_soft_shadow_kernel[32];
float4 penumbra_shadow_kernel[32];
float4 soft_shadow_kernel[32];
float2 shadow_atlas_pixel_size;
float2 directional_shadow_pixel_size;
uint directional_light_count;
float dual_paraboloid_side;
float z_far;
float z_near;
float roughness_limiter_amount;
float roughness_limiter_limit;
float opaque_prepass_threshold;
uint flags;
float3x3 radiance_inverse_xform;
float4 ambient_light_color_energy;
float ambient_color_sky_mix;
float fog_density;
float fog_height;
float fog_height_density;
float fog_depth_curve;
float fog_depth_begin;
float fog_depth_end;
float fog_sun_scatter;
packed_float3 fog_light_color;
float fog_aerial_perspective;
float time;
float taa_frame_count;
float2 taa_jitter;
float emissive_exposure_normalization;
float IBL_exposure_normalization;
uint camera_visible_layers;
float pass_alpha_multiplier;
};
struct SceneDataBlock
{
SceneData data;
SceneData prev_data;
};
constant uint pso_sc_packed_1_tmp [[function_constant(1)]];
constant uint pso_sc_packed_1 = is_function_constant_defined(pso_sc_packed_1_tmp) ? pso_sc_packed_1_tmp : 0u;
constant float pso_sc_packed_2_tmp [[function_constant(2)]];
constant float pso_sc_packed_2 = is_function_constant_defined(pso_sc_packed_2_tmp) ? pso_sc_packed_2_tmp : 2.0;
struct LightData
{
packed_float3 position;
float inv_radius;
packed_float3 direction;
float size;
packed_float3 color;
float attenuation;
float cone_attenuation;
float cone_angle;
float specular_amount;
float shadow_opacity;
float4 atlas_rect;
float4x4 shadow_matrix;
float shadow_bias;
float shadow_normal_bias;
float transmittance_bias;
float soft_shadow_size;
float soft_shadow_scale;
uint mask;
float volumetric_fog_energy;
uint bake_mode;
float4 projector_rect;
};
struct OmniLights
{
LightData data[1];
};
struct SpotLights
{
LightData data[1];
};
struct ReflectionData
{
packed_float3 box_extents;
float index;
packed_float3 box_offset;
uint mask;
packed_float3 ambient;
float intensity;
float blend_distance;
uint exterior;
uint box_project;
uint ambient_mode;
float exposure_normalization;
float pad0;
float pad1;
float pad2;
float4x4 local_matrix;
};
struct ReflectionProbeData
{
ReflectionData data[1];
};
struct DirectionalLightData
{
packed_float3 direction;
float energy;
packed_float3 color;
float size;
float specular;
uint mask;
float softshadow_angle;
float soft_shadow_scale;
uint blend_splits;
float shadow_opacity;
float fade_from;
float fade_to;
uint2 pad;
uint bake_mode;
float volumetric_fog_energy;
float4 shadow_bias;
float4 shadow_normal_bias;
float4 shadow_transmittance_bias;
float4 shadow_z_range;
float4 shadow_range_begin;
float4 shadow_split_offsets;
float4x4 shadow_matrix1;
float4x4 shadow_matrix2;
float4x4 shadow_matrix3;
float4x4 shadow_matrix4;
float2 uv_scale1;
float2 uv_scale2;
float2 uv_scale3;
float2 uv_scale4;
};
struct DirectionalLights
{
DirectionalLightData data[8];
};
struct Lightmap
{
float3x3 normal_xform;
float2 light_texture_size;
float exposure_normalization;
uint flags;
};
struct Lightmaps
{
Lightmap data[1];
};
struct LightmapCapture
{
float4 sh[9];
};
struct LightmapCaptures
{
LightmapCapture data[1];
};
struct DecalData
{
float4x4 xform;
packed_float3 inv_extents;
float albedo_mix;
float4 albedo_rect;
float4 normal_rect;
float4 orm_rect;
float4 emission_rect;
float4 modulate;
float emission_energy;
uint mask;
float upper_fade;
float lower_fade;
float3x4 normal_xform;
packed_float3 normal;
float normal_fade;
};
struct Decals
{
DecalData data[1];
};
struct GlobalShaderUniformData
{
float4 data[1];
};
struct spvDescriptorSetBuffer0
{
sampler shadow_sampler [[id(0)]];
const device OmniLights* omni_lights [[id(1)]];
const device SpotLights* spot_lights [[id(2)]];
const device ReflectionProbeData* reflections [[id(3)]];
constant DirectionalLights* directional_lights [[id(4)]];
const device Lightmaps* lightmaps [[id(5)]];
const device LightmapCaptures* lightmap_captures [[id(6)]];
texture2d<float> decal_atlas [[id(7)]];
texture2d<float> decal_atlas_srgb [[id(8)]];
const device Decals* decals [[id(9)]];
const device GlobalShaderUniformData* global_shader_uniforms [[id(10)]];
sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP [[id(11)]];
};
struct spvDescriptorSetBuffer1
{
const device InstanceDataBuffer* instances [[id(0)]];
constant SceneDataBlock* scene_data_block [[id(1)]];
texturecube_array<float> radiance_cubemap [[id(2)]];
texturecube_array<float> reflection_atlas [[id(3)]];
texture2d<float> shadow_atlas [[id(4)]];
texture2d<float> directional_shadow_atlas [[id(5)]];
array<texture2d_array<float>, 16> lightmap_textures [[id(6)]];
texture2d<float> depth_buffer [[id(22)]];
texture2d<float> color_buffer [[id(23)]];
sampler decal_sampler [[id(24)]];
sampler light_projector_sampler [[id(25)]];
sampler SAMPLER_NEAREST_CLAMP [[id(26)]];
sampler SAMPLER_LINEAR_CLAMP [[id(27)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP [[id(28)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP [[id(29)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP [[id(30)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP [[id(31)]];
sampler SAMPLER_NEAREST_REPEAT [[id(32)]];
sampler SAMPLER_LINEAR_REPEAT [[id(33)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT [[id(34)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT [[id(35)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT [[id(36)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT [[id(37)]];
};
struct spvDescriptorSetBuffer2
{
const device Transforms* transforms [[id(0)]];
};
struct main0_out
{
float3 vertex_interp [[user(locn0)]];
float3 normal_interp [[user(locn1)]];
float4 gl_Position [[position, invariant]];
};
struct main0_in
{
float4 vertex_angle_attrib [[attribute(0)]];
float4 axis_tangent_attrib [[attribute(1)]];
};
static inline __attribute__((always_inline))
float3 oct_to_vec3(thread const float2& e)
{
float3 v = float3(e, (1.0 - abs(e.x)) - abs(e.y));
float t = fast::max(-v.z, 0.0);
float3 _129 = v;
float3 _134 = v;
float2 _136 = _134.xy + ((-sign(_129.xy)) * t);
v.x = _136.x;
v.y = _136.y;
return fast::normalize(v);
}
static inline __attribute__((always_inline))
void axis_angle_to_tbn(thread const float3& axis, thread const float& angle, thread float3& tangent, thread float3& binormal, thread float3& normal)
{
float c = cos(angle);
float s = sin(angle);
float3 omc_axis = axis * (1.0 - c);
float3 s_axis = axis * s;
tangent = (omc_axis.xxx * axis) + float3(c, -s_axis.z, s_axis.y);
binormal = (omc_axis.yyy * axis) + float3(s_axis.z, c, -s_axis.x);
normal = (omc_axis.zzz * axis) + float3(-s_axis.y, s_axis.x, c);
}
static inline __attribute__((always_inline))
void _unpack_vertex_attributes(thread const float4& p_vertex_in, thread const float3& p_compressed_aabb_position, thread const float3& p_compressed_aabb_size, thread const float4& p_normal_in, thread float3& r_normal, thread float3& r_tangent, thread float3& r_binormal, thread float3& r_vertex)
{
r_vertex = (p_vertex_in.xyz * p_compressed_aabb_size) + p_compressed_aabb_position;
float2 param = (p_normal_in.xy * 2.0) - float2(1.0);
r_normal = oct_to_vec3(param);
bool _233 = p_normal_in.z > 0.0;
bool _241;
if (!_233)
{
_241 = p_normal_in.w < 1.0;
}
else
{
_241 = _233;
}
float binormal_sign;
if (_241)
{
float2 signed_tangent_attrib = (p_normal_in.zw * 2.0) - float2(1.0);
float2 param_1 = float2(signed_tangent_attrib.x, (abs(signed_tangent_attrib.y) * 2.0) - 1.0);
r_tangent = oct_to_vec3(param_1);
binormal_sign = sign(signed_tangent_attrib.y);
r_binormal = fast::normalize(cross(r_normal, r_tangent) * binormal_sign);
}
else
{
float angle = p_vertex_in.w;
binormal_sign = (angle > 0.5) ? 1.0 : (-1.0);
angle = abs((angle * 2.0) - 1.0) * 3.1415927410125732421875;
float3 axis = r_normal;
float3 param_2 = axis;
float param_3 = angle;
float3 param_4;
float3 param_5;
float3 param_6;
axis_angle_to_tbn(param_2, param_3, param_4, param_5, param_6);
r_tangent = param_4;
r_binormal = param_5;
r_normal = param_6;
r_binormal *= binormal_sign;
}
}
static inline __attribute__((always_inline))
uint sc_packed_0()
{
return pso_sc_packed_0;
}
static inline __attribute__((always_inline))
bool sc_multimesh()
{
return ((sc_packed_0() >> uint(11)) & 1u) != 0u;
}
static inline __attribute__((always_inline))
bool sc_multimesh_format_2d()
{
return ((sc_packed_0() >> uint(12)) & 1u) != 0u;
}
static inline __attribute__((always_inline))
bool sc_multimesh_has_color()
{
return ((sc_packed_0() >> uint(13)) & 1u) != 0u;
}
static inline __attribute__((always_inline))
bool sc_multimesh_has_custom_data()
{
return ((sc_packed_0() >> uint(14)) & 1u) != 0u;
}
static inline __attribute__((always_inline))
uint multimesh_stride()
{
uint stride = uint(sc_multimesh_format_2d() ? 2 : 3);
stride += uint(int(sc_multimesh_has_color()));
stride += uint(int(sc_multimesh_has_custom_data()));
return stride;
}
static inline __attribute__((always_inline))
void vertex_shader(thread float3& vertex0, thread float3& normal_highp, thread const float3& tangent_highp, thread const float3& binormal_highp, thread const uint& instance_index, thread const uint& multimesh_offset, thread float4x4& model_matrix, thread const float4x4& projection_matrix, thread const float4x4& inv_projection_matrix, thread const float4x4& view_matrix, thread const float4x4& inv_view_matrix, thread const float2& viewport_size, thread const uint& scene_directional_light_count, thread const float4& screen_position_output, const device InstanceDataBuffer& instances, thread uint& gl_InstanceIndex, const device Transforms& transforms, thread float3& vertex_interp, thread float3& normal_interp, thread float4& gl_Position)
{
float4 instance_custom = float4(0.0);
float3x3 model_normal_matrix;
if ((instances.data[instance_index].flags & 16u) != 0u)
{
model_normal_matrix = transpose(spvInverse3x3(float3x3(model_matrix[0].xyz, model_matrix[1].xyz, model_matrix[2].xyz)));
}
else
{
model_normal_matrix = float3x3(model_matrix[0].xyz, model_matrix[1].xyz, model_matrix[2].xyz);
}
float4x4 read_model_matrix = model_matrix;
if (sc_multimesh())
{
uint stride = multimesh_stride();
uint offset = stride * (uint(int(gl_InstanceIndex)) + multimesh_offset);
float4x4 matrix;
if (sc_multimesh_format_2d())
{
matrix = float4x4(float4(transforms.data[offset + 0u]), float4(transforms.data[offset + 1u]), float4(0.0, 0.0, 1.0, 0.0), float4(0.0, 0.0, 0.0, 1.0));
offset += 2u;
}
else
{
matrix = float4x4(float4(transforms.data[offset + 0u]), float4(transforms.data[offset + 1u]), float4(transforms.data[offset + 2u]), float4(0.0, 0.0, 0.0, 1.0));
offset += 3u;
}
if (sc_multimesh_has_color())
{
offset++;
}
if (sc_multimesh_has_custom_data())
{
instance_custom = transforms.data[offset];
}
matrix = transpose(matrix);
read_model_matrix = model_matrix * matrix;
model_matrix = read_model_matrix;
model_normal_matrix = model_normal_matrix * float3x3(matrix[0].xyz, matrix[1].xyz, matrix[2].xyz);
}
float4 uv_scale = instances.data[instance_index].uv_scale;
if (any(uv_scale != float4(0.0)))
{
}
float3 eye_offset = float3(0.0);
float roughness_highp = 1.0;
float4x4 modelview = view_matrix * model_matrix;
float3x3 modelview_normal = float3x3(view_matrix[0].xyz, view_matrix[1].xyz, view_matrix[2].xyz) * model_normal_matrix;
float4x4 read_view_matrix = view_matrix;
float2 read_viewport_size = viewport_size;
half roughness = half(roughness_highp);
vertex0 = (modelview * float4(vertex0, 1.0)).xyz;
normal_highp = modelview_normal * normal_highp;
vertex_interp = vertex0;
normal_interp = float3(half3(fast::normalize(normal_highp)));
float4 _527 = float4(vertex_interp, 1.0);
float4 _528 = projection_matrix * _527;
gl_Position = _528;
}
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], constant spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(1)]], constant spvDescriptorSetBuffer2& spvDescriptorSet2 [[buffer(2)]], constant DrawCall& draw_call [[buffer(3)]], uint gl_InstanceIndex [[instance_id]])
{
main0_out out = {};
float4 param = in.vertex_angle_attrib;
float3 param_1 = (*spvDescriptorSet1.instances).data[draw_call.instance_index].compressed_aabb_position_pad.xyz;
float3 param_2 = (*spvDescriptorSet1.instances).data[draw_call.instance_index].compressed_aabb_size_pad.xyz;
float4 param_3 = in.axis_tangent_attrib;
float3 param_4;
float3 param_5;
float3 param_6;
float3 param_7;
_unpack_vertex_attributes(param, param_1, param_2, param_3, param_4, param_5, param_6, param_7);
float3 normal = param_4;
float3 tangent = param_5;
float3 binormal = param_6;
float3 vertex0 = param_7;
float3 param_8 = vertex0;
float3 param_9 = normal;
float3 param_10 = tangent;
float3 param_11 = binormal;
uint param_12 = draw_call.instance_index;
uint param_13 = draw_call.multimesh_motion_vectors_current_offset;
float4x4 param_14 = (*spvDescriptorSet1.instances).data[draw_call.instance_index].transform;
float4x4 param_15 = (*spvDescriptorSet1.scene_data_block).data.projection_matrix;
float4x4 param_16 = (*spvDescriptorSet1.scene_data_block).data.inv_projection_matrix;
float4x4 param_17 = (*spvDescriptorSet1.scene_data_block).data.view_matrix;
float4x4 param_18 = (*spvDescriptorSet1.scene_data_block).data.inv_view_matrix;
float2 param_19 = (*spvDescriptorSet1.scene_data_block).data.viewport_size;
uint param_20 = (*spvDescriptorSet1.scene_data_block).data.directional_light_count;
float4 param_21;
vertex_shader(param_8, param_9, param_10, param_11, param_12, param_13, param_14, param_15, param_16, param_17, param_18, param_19, param_20, param_21, (*spvDescriptorSet1.instances), gl_InstanceIndex, (*spvDescriptorSet2.transforms), out.vertex_interp, out.normal_interp, out.gl_Position);
float4 screen_position = param_21;
out.gl_Position.y = -(out.gl_Position.y); // Invert Y-axis for Metal
return out;
}
Fragment:
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
// Returns the determinant of a 2x2 matrix.
static inline __attribute__((always_inline))
float spvDet2x2(float a1, float a2, float b1, float b2)
{
return a1 * b2 - b1 * a2;
}
// Returns the inverse of a matrix, by using the algorithm of calculating the classical
// adjoint and dividing by the determinant. The contents of the matrix are changed.
static inline __attribute__((always_inline))
float3x3 spvInverse3x3(float3x3 m)
{
float3x3 adj; // The adjoint matrix (inverse after dividing by determinant)
// Create the transpose of the cofactors, as the classical adjoint of the matrix.
adj[0][0] = spvDet2x2(m[1][1], m[1][2], m[2][1], m[2][2]);
adj[0][1] = -spvDet2x2(m[0][1], m[0][2], m[2][1], m[2][2]);
adj[0][2] = spvDet2x2(m[0][1], m[0][2], m[1][1], m[1][2]);
adj[1][0] = -spvDet2x2(m[1][0], m[1][2], m[2][0], m[2][2]);
adj[1][1] = spvDet2x2(m[0][0], m[0][2], m[2][0], m[2][2]);
adj[1][2] = -spvDet2x2(m[0][0], m[0][2], m[1][0], m[1][2]);
adj[2][0] = spvDet2x2(m[1][0], m[1][1], m[2][0], m[2][1]);
adj[2][1] = -spvDet2x2(m[0][0], m[0][1], m[2][0], m[2][1]);
adj[2][2] = spvDet2x2(m[0][0], m[0][1], m[1][0], m[1][1]);
// Calculate the determinant as a combination of the cofactors of the first row.
float det = (adj[0][0] * m[0][0]) + (adj[0][1] * m[1][0]) + (adj[0][2] * m[2][0]);
// Divide the classical adjoint matrix by the determinant.
// If determinant is zero, matrix is not invertable, so leave it unchanged.
return (det != 0.0f) ? (adj * (1.0f / det)) : m;
}
constant uint pso_sc_packed_0_tmp [[function_constant(0)]];
constant uint pso_sc_packed_0 = is_function_constant_defined(pso_sc_packed_0_tmp) ? pso_sc_packed_0_tmp : 0u;
constant uint pso_sc_packed_1_tmp [[function_constant(1)]];
constant uint pso_sc_packed_1 = is_function_constant_defined(pso_sc_packed_1_tmp) ? pso_sc_packed_1_tmp : 0u;
constant float pso_sc_packed_2_tmp [[function_constant(2)]];
constant float pso_sc_packed_2 = is_function_constant_defined(pso_sc_packed_2_tmp) ? pso_sc_packed_2_tmp : 2.0;
struct SceneData
{
float4x4 projection_matrix;
float4x4 inv_projection_matrix;
float4x4 inv_view_matrix;
float4x4 view_matrix;
float4x4 projection_matrix_view[2];
float4x4 inv_projection_matrix_view[2];
float4 eye_offset[2];
float4x4 main_cam_inv_view_matrix;
float2 viewport_size;
float2 screen_pixel_size;
float4 directional_penumbra_shadow_kernel[32];
float4 directional_soft_shadow_kernel[32];
float4 penumbra_shadow_kernel[32];
float4 soft_shadow_kernel[32];
float2 shadow_atlas_pixel_size;
float2 directional_shadow_pixel_size;
uint directional_light_count;
float dual_paraboloid_side;
float z_far;
float z_near;
float roughness_limiter_amount;
float roughness_limiter_limit;
float opaque_prepass_threshold;
uint flags;
float3x3 radiance_inverse_xform;
float4 ambient_light_color_energy;
float ambient_color_sky_mix;
float fog_density;
float fog_height;
float fog_height_density;
float fog_depth_curve;
float fog_depth_begin;
float fog_depth_end;
float fog_sun_scatter;
packed_float3 fog_light_color;
float fog_aerial_perspective;
float time;
float taa_frame_count;
float2 taa_jitter;
float emissive_exposure_normalization;
float IBL_exposure_normalization;
uint camera_visible_layers;
float pass_alpha_multiplier;
};
struct SceneDataBlock
{
SceneData data;
SceneData prev_data;
};
struct InstanceData
{
float4x4 transform;
float4x4 prev_transform;
uint flags;
uint instance_uniforms_ofs;
uint gi_offset;
uint layer_mask;
float4 lightmap_uv_scale;
uint2 reflection_probes;
uint2 omni_lights;
uint2 spot_lights;
uint2 decals;
float4 compressed_aabb_position_pad;
float4 compressed_aabb_size_pad;
float4 uv_scale;
};
struct InstanceDataBuffer
{
InstanceData data[1];
};
struct DrawCall
{
uint uv_offset;
uint instance_index;
uint multimesh_motion_vectors_current_offset;
uint multimesh_motion_vectors_previous_offset;
};
struct DecalData
{
float4x4 xform;
packed_float3 inv_extents;
float albedo_mix;
float4 albedo_rect;
float4 normal_rect;
float4 orm_rect;
float4 emission_rect;
float4 modulate;
float emission_energy;
uint mask;
float upper_fade;
float lower_fade;
float3x4 normal_xform;
packed_float3 normal;
float normal_fade;
};
struct Decals
{
DecalData data[1];
};
struct LightData
{
packed_float3 position;
float inv_radius;
packed_float3 direction;
float size;
packed_float3 color;
float attenuation;
float cone_attenuation;
float cone_angle;
float specular_amount;
float shadow_opacity;
float4 atlas_rect;
float4x4 shadow_matrix;
float shadow_bias;
float shadow_normal_bias;
float transmittance_bias;
float soft_shadow_size;
float soft_shadow_scale;
uint mask;
float volumetric_fog_energy;
uint bake_mode;
float4 projector_rect;
};
struct OmniLights
{
LightData data[1];
};
struct SpotLights
{
LightData data[1];
};
struct ReflectionData
{
packed_float3 box_extents;
float index;
packed_float3 box_offset;
uint mask;
packed_float3 ambient;
float intensity;
float blend_distance;
uint exterior;
uint box_project;
uint ambient_mode;
float exposure_normalization;
float pad0;
float pad1;
float pad2;
float4x4 local_matrix;
};
struct ReflectionProbeData
{
ReflectionData data[1];
};
struct DirectionalLightData
{
packed_float3 direction;
float energy;
packed_float3 color;
float size;
float specular;
uint mask;
float softshadow_angle;
float soft_shadow_scale;
uint blend_splits;
float shadow_opacity;
float fade_from;
float fade_to;
uint2 pad;
uint bake_mode;
float volumetric_fog_energy;
float4 shadow_bias;
float4 shadow_normal_bias;
float4 shadow_transmittance_bias;
float4 shadow_z_range;
float4 shadow_range_begin;
float4 shadow_split_offsets;
float4x4 shadow_matrix1;
float4x4 shadow_matrix2;
float4x4 shadow_matrix3;
float4x4 shadow_matrix4;
float2 uv_scale1;
float2 uv_scale2;
float2 uv_scale3;
float2 uv_scale4;
};
struct DirectionalLights
{
DirectionalLightData data[8];
};
struct Lightmap
{
float3x3 normal_xform;
float2 light_texture_size;
float exposure_normalization;
uint flags;
};
struct Lightmaps
{
Lightmap data[1];
};
struct LightmapCapture
{
float4 sh[9];
};
struct LightmapCaptures
{
LightmapCapture data[1];
};
struct GlobalShaderUniformData
{
float4 data[1];
};
struct Transforms
{
float4 data[1];
};
struct spvDescriptorSetBuffer0
{
const device Decals* decals [[id(0)]];
texture2d<float> decal_atlas_srgb [[id(1)]];
texture2d<float> decal_atlas [[id(2)]];
sampler shadow_sampler [[id(3)]];
const device OmniLights* omni_lights [[id(4)]];
const device SpotLights* spot_lights [[id(5)]];
const device ReflectionProbeData* reflections [[id(6)]];
constant DirectionalLights* directional_lights [[id(7)]];
const device Lightmaps* lightmaps [[id(8)]];
const device LightmapCaptures* lightmap_captures [[id(9)]];
const device GlobalShaderUniformData* global_shader_uniforms [[id(10)]];
sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP [[id(11)]];
};
struct spvDescriptorSetBuffer1
{
constant SceneDataBlock* scene_data_block [[id(0)]];
const device InstanceDataBuffer* instances [[id(1)]];
sampler decal_sampler [[id(2)]];
texturecube_array<float> radiance_cubemap [[id(3)]];
texturecube_array<float> reflection_atlas [[id(4)]];
texture2d<float> shadow_atlas [[id(5)]];
texture2d<float> directional_shadow_atlas [[id(6)]];
array<texture2d_array<float>, 16> lightmap_textures [[id(7)]];
texture2d<float> depth_buffer [[id(23)]];
texture2d<float> color_buffer [[id(24)]];
sampler light_projector_sampler [[id(25)]];
sampler SAMPLER_NEAREST_CLAMP [[id(26)]];
sampler SAMPLER_LINEAR_CLAMP [[id(27)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP [[id(28)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP [[id(29)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP [[id(30)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP [[id(31)]];
sampler SAMPLER_NEAREST_REPEAT [[id(32)]];
sampler SAMPLER_LINEAR_REPEAT [[id(33)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT [[id(34)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT [[id(35)]];
sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT [[id(36)]];
sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT [[id(37)]];
};
struct spvDescriptorSetBuffer2
{
const device Transforms* transforms [[id(0)]];
};
struct main0_out
{
float4 frag_color [[color(0)]];
};
struct main0_in
{
float3 vertex_interp [[user(locn0)]];
float3 normal_interp [[user(locn1)]];
};
static inline __attribute__((always_inline))
uint sc_packed_1()
{
return pso_sc_packed_1;
}
static inline __attribute__((always_inline))
uint sc_decals(thread const uint& bound)
{
if (((sc_packed_1() >> uint(20)) & 1u) != 0u)
{
return bound;
}
else
{
return 0u;
}
}
static inline __attribute__((always_inline))
uint sc_packed_0()
{
return pso_sc_packed_0;
}
static inline __attribute__((always_inline))
bool sc_decal_use_mipmaps()
{
return ((sc_packed_0() >> uint(3)) & 1u) != 0u;
}
static inline __attribute__((always_inline))
bool sc_scene_roughness_limiter_enabled()
{
return ((sc_packed_0() >> uint(17)) & 1u) != 0u;
}
static inline __attribute__((always_inline))
float sc_packed_2()
{
return pso_sc_packed_2;
}
static inline __attribute__((always_inline))
half sc_luminance_multiplier()
{
return half(sc_packed_2());
}
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], constant spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(1)]], constant spvDescriptorSetBuffer2& spvDescriptorSet2 [[buffer(2)]], constant DrawCall& draw_call [[buffer(3)]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
float3 vertex0 = in.vertex_interp;
float3 eye_offset = float3(0.0);
float3 view_highp = -fast::normalize(in.vertex_interp);
float3 albedo_highp = float3(1.0);
float3 backlight_highp = float3(0.0);
float4 transmittance_color_highp = float4(0.0);
float transmittance_depth_highp = 0.0;
float transmittance_boost_highp = 0.0;
float metallic_highp = 0.0;
float specular_highp = 0.5;
float3 emission_highp = float3(0.0);
float roughness_highp = 1.0;
float rim_highp = 0.0;
float rim_tint_highp = 0.0;
float clearcoat_highp = 0.0;
float clearcoat_roughness_highp = 0.0;
float anisotropy_highp = 0.0;
float2 anisotropy_flow_highp = float2(1.0, 0.0);
float ao_highp = 1.0;
float ao_light_affect_highp = 0.0;
float alpha_highp = 1.0;
float3 binormal_highp = float3(0.0);
float3 tangent_highp = float3(0.0);
float3 normal_highp = in.normal_interp;
float normal_map_depth_highp = 1.0;
float2 screen_uv = gl_FragCoord.xy * (*spvDescriptorSet1.scene_data_block).data.screen_pixel_size;
float sss_strength_highp = 0.0;
float4x4 inv_view_matrix = (*spvDescriptorSet1.scene_data_block).data.inv_view_matrix;
float4x4 read_model_matrix = (*spvDescriptorSet1.instances).data[draw_call.instance_index].transform;
float3x3 model_normal_matrix;
if (((*spvDescriptorSet1.instances).data[draw_call.instance_index].flags & 16u) != 0u)
{
model_normal_matrix = transpose(spvInverse3x3(float3x3(read_model_matrix[0].xyz, read_model_matrix[1].xyz, read_model_matrix[2].xyz)));
}
else
{
model_normal_matrix = float3x3(read_model_matrix[0].xyz, read_model_matrix[1].xyz, read_model_matrix[2].xyz);
}
float4x4 read_view_matrix = (*spvDescriptorSet1.scene_data_block).data.view_matrix;
float2 read_viewport_size = (*spvDescriptorSet1.scene_data_block).data.viewport_size;
albedo_highp = float3(1.0, 0.0, 0.0);
half3 view = half3(view_highp);
half3 albedo = half3(albedo_highp);
half3 backlight = half3(backlight_highp);
half4 transmittance_color = half4(transmittance_color_highp);
half transmittance_depth = half(transmittance_depth_highp);
half transmittance_boost = half(transmittance_boost_highp);
half metallic = half(metallic_highp);
half specular = half(specular_highp);
half3 emission = half3(emission_highp);
half roughness = half(roughness_highp);
half rim = half(rim_highp);
half rim_tint = half(rim_tint_highp);
half clearcoat = half(clearcoat_highp);
half clearcoat_roughness = half(clearcoat_roughness_highp);
half anisotropy = half(anisotropy_highp);
half2 anisotropy_flow = half2(anisotropy_flow_highp);
half ao = half(ao_highp);
half ao_light_affect = half(ao_light_affect_highp);
half alpha = half(alpha_highp);
half normal_map_depth = half(normal_map_depth_highp);
half sss_strength = half(sss_strength_highp);
half3 binormal = half3(binormal_highp);
half3 tangent = half3(tangent_highp);
half3 normal = half3(normal_highp);
half3 geo_normal = normalize(normal);
normal = geo_normal;
float3 vertex_ddx = dfdx(vertex0);
float3 vertex_ddy = dfdy(vertex0);
uint param = 8u;
uint decal_count = sc_decals(param);
uint2 decal_indices = (*spvDescriptorSet1.instances).data[draw_call.instance_index].decals;
uint _323;
float _385;
float _399;
float4 decal_albedo;
float3 decal_normal;
float3 decal_orm;
for (uint i = 0u; i < decal_count; i++)
{
if (i > 3u)
{
_323 = (decal_indices.y >> ((i - 4u) * 8u)) & 255u;
}
else
{
_323 = (decal_indices.x >> (i * 8u)) & 255u;
}
uint decal_index = _323;
if (decal_index == 255u)
{
break;
}
float3 uv_local = ((*spvDescriptorSet0.decals).data[decal_index].xform * float4(vertex0, 1.0)).xyz;
bool _370 = any(uv_local < float3(0.0, -1.0, 0.0));
bool _377;
if (!_370)
{
_377 = any(uv_local > float3(1.0));
}
else
{
_377 = _370;
}
if (_377)
{
continue;
}
if (uv_local.y > 0.0)
{
_385 = uv_local.y;
}
else
{
_385 = -uv_local.y;
}
if (uv_local.y > 0.0)
{
_399 = (*spvDescriptorSet0.decals).data[decal_index].upper_fade;
}
else
{
_399 = (*spvDescriptorSet0.decals).data[decal_index].lower_fade;
}
float fade = powr(1.0 - _385, _399);
if ((*spvDescriptorSet0.decals).data[decal_index].normal_fade > 0.0)
{
fade *= smoothstep((*spvDescriptorSet0.decals).data[decal_index].normal_fade, 1.0, (dot(float3(geo_normal), float3((*spvDescriptorSet0.decals).data[decal_index].normal)) * 0.5) + 0.5);
}
float2 ddx = ((*spvDescriptorSet0.decals).data[decal_index].xform * float4(vertex_ddx, 0.0)).xz;
float2 ddy = ((*spvDescriptorSet0.decals).data[decal_index].xform * float4(vertex_ddy, 0.0)).xz;
if (any((*spvDescriptorSet0.decals).data[decal_index].albedo_rect != float4(0.0)))
{
if (sc_decal_use_mipmaps())
{
decal_albedo = spvDescriptorSet0.decal_atlas_srgb.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].albedo_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].albedo_rect.xy), gradient2d(ddx * (*spvDescriptorSet0.decals).data[decal_index].albedo_rect.zw, ddy * (*spvDescriptorSet0.decals).data[decal_index].albedo_rect.zw));
}
else
{
decal_albedo = spvDescriptorSet0.decal_atlas_srgb.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].albedo_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].albedo_rect.xy), level(0.0));
}
decal_albedo *= (*spvDescriptorSet0.decals).data[decal_index].modulate;
decal_albedo.w *= fade;
albedo = half3(mix(float3(albedo), decal_albedo.xyz, float3(decal_albedo.w * (*spvDescriptorSet0.decals).data[decal_index].albedo_mix)));
if (any((*spvDescriptorSet0.decals).data[decal_index].normal_rect != float4(0.0)))
{
if (sc_decal_use_mipmaps())
{
decal_normal = spvDescriptorSet0.decal_atlas.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].normal_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].normal_rect.xy), gradient2d(ddx * (*spvDescriptorSet0.decals).data[decal_index].normal_rect.zw, ddy * (*spvDescriptorSet0.decals).data[decal_index].normal_rect.zw)).xyz;
}
else
{
decal_normal = spvDescriptorSet0.decal_atlas.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].normal_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].normal_rect.xy), level(0.0)).xyz;
}
float3 _607 = decal_normal;
float2 _614 = (_607.xy * float2(2.0, -2.0)) - float2(1.0, -1.0);
decal_normal.x = _614.x;
decal_normal.y = _614.y;
decal_normal.z = sqrt(fast::max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
decal_normal = ((*spvDescriptorSet0.decals).data[decal_index].normal_xform * decal_normal.xzy).xyz;
normal = half3(fast::normalize(mix(float3(normal), decal_normal, float3(decal_albedo.w))));
}
if (any((*spvDescriptorSet0.decals).data[decal_index].orm_rect != float4(0.0)))
{
if (sc_decal_use_mipmaps())
{
decal_orm = spvDescriptorSet0.decal_atlas.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].orm_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].orm_rect.xy), gradient2d(ddx * (*spvDescriptorSet0.decals).data[decal_index].orm_rect.zw, ddy * (*spvDescriptorSet0.decals).data[decal_index].orm_rect.zw)).xyz;
}
else
{
decal_orm = spvDescriptorSet0.decal_atlas.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].orm_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].orm_rect.xy), level(0.0)).xyz;
}
ao = half(mix(float(ao), decal_orm.x, decal_albedo.w));
roughness = half(mix(float(roughness), decal_orm.y, decal_albedo.w));
metallic = half(mix(float(metallic), decal_orm.z, decal_albedo.w));
}
}
if (any((*spvDescriptorSet0.decals).data[decal_index].emission_rect != float4(0.0)))
{
if (sc_decal_use_mipmaps())
{
emission += half3((spvDescriptorSet0.decal_atlas_srgb.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].emission_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].emission_rect.xy), gradient2d(ddx * (*spvDescriptorSet0.decals).data[decal_index].emission_rect.zw, ddy * (*spvDescriptorSet0.decals).data[decal_index].emission_rect.zw)).xyz * (*spvDescriptorSet0.decals).data[decal_index].emission_energy) * fade);
}
else
{
emission += half3((spvDescriptorSet0.decal_atlas_srgb.sample(spvDescriptorSet1.decal_sampler, ((uv_local.xz * (*spvDescriptorSet0.decals).data[decal_index].emission_rect.zw) + (*spvDescriptorSet0.decals).data[decal_index].emission_rect.xy), level(0.0)).xyz * (*spvDescriptorSet0.decals).data[decal_index].emission_energy) * fade);
}
}
}
if (sc_scene_roughness_limiter_enabled())
{
float3 dn = float3(normal);
float3 dndu = dfdx(dn);
float3 dndv = dfdy(dn);
half roughness2 = roughness * roughness;
half variance = half((*spvDescriptorSet1.scene_data_block).data.roughness_limiter_amount) * half(dot(dndu, dndu) + dot(dndv, dndv));
half kernelRoughness2 = min(half(2.0) * variance, half((*spvDescriptorSet1.scene_data_block).data.roughness_limiter_limit));
half filteredRoughness2 = min(half(1.0), roughness2 + kernelRoughness2);
roughness = sqrt(filteredRoughness2);
}
half3 indirect_specular_light = half3(half(0.0));
half3 direct_specular_light = half3(half(0.0));
half3 diffuse_light = half3(half(0.0));
half3 ambient_light = half3(half(0.0));
diffuse_light *= albedo;
diffuse_light *= ao;
direct_specular_light *= ao;
diffuse_light *= (half(1.0) - metallic);
ambient_light *= (half(1.0) - metallic);
half4 out_color = half4(albedo, alpha);
half4 _884 = out_color;
half3 _888 = _884.xyz / half3(sc_luminance_multiplier());
out_color.x = _888.x;
out_color.y = _888.y;
out_color.z = _888.z;
out.frag_color = float4(out_color);
return out;
}
Steps to reproduce
Open and run the attached project. Check the auto-generated native shader code.