Merge branch 'main' into feature/h2c_support_clean

This commit is contained in:
Rodrigo Faselli
2026-07-12 22:00:40 -03:00
committed by GitHub
65 changed files with 3958 additions and 1183 deletions

View File

@@ -55,6 +55,15 @@ const float ONE_OVER_EPSILON = 1e4;
uniform float z_far;
uniform float z_near;
// Depth-based shadow map (object-on-object and self shadows). shadow_intensity == 0 disables it.
uniform sampler2D shadow_map;
uniform mat4 shadow_light_vp;
uniform float shadow_intensity;
uniform float shadow_map_texel;
// LIGHT_TOP_DIR in eye space (matches the diffuse light used for shading in gouraud.vs).
const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
varying vec3 clipping_planes_dots;
varying float color_clip_plane_dot;
@@ -130,6 +139,35 @@ float DetectSilho(vec2 fragCoord)
);
}
// Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is
// occluded from the light in the shadow map. 3x3 PCF softens the edges.
float shadow_shade()
{
if (shadow_intensity <= 0.0)
return 1.0;
vec4 lp = shadow_light_vp * world_pos;
vec3 proj = lp.xyz / lp.w;
proj = proj * 0.5 + 0.5;
if (proj.z > 1.0)
return 1.0;
// Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This
// suppresses self-shadow acne without discarding real shadows cast by other objects onto
// back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow).
float NdotL = dot(normalize(eye_normal), SHADOW_LIGHT_DIR);
float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));
// 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne.
float sum = 0.0;
for (int x = -2; x <= 2; ++x) {
for (int y = -2; y <= 2; ++y) {
float closest = texture2D(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;
sum += (proj.z - bias > closest) ? 1.0 : 0.0;
}
}
return 1.0 - shadow_intensity * (sum / 25.0);
}
void main()
{
if (any(lessThan(clipping_planes_dots, ZERO)))
@@ -180,10 +218,11 @@ void main()
bool is_out_printable_height = (all(greaterThan(eph_check_min, vec3(1.0))) && all(lessThan(eph_check_max, vec3(1.0))));
color.rgb = is_out_printable_height ? mix(color.rgb, ZERO, 0.7) : color.rgb;
}
float shade = shadow_shade();
//BBS: add outline_color
if (is_outline) {
color = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a);
color = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a);
vec2 fragCoord = gl_FragCoord.xy;
float s = DetectSilho(fragCoord);
// Makes silhouettes thicker.
@@ -191,13 +230,13 @@ void main()
{
s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0)));
s = max(s, DetectSilho(fragCoord.xy + vec2(0, i)));
}
}
gl_FragColor = vec4(mix(color.rgb, getBackfaceColor(color.rgb), s), color.a);
}
#ifdef ENABLE_ENVIRONMENT_MAP
else if (use_environment_tex)
gl_FragColor = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a);
gl_FragColor = vec4((0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x) * shade, color.a);
#endif
else
gl_FragColor = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a);
gl_FragColor = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a);
}

View File

@@ -65,6 +65,12 @@ uniform float z_far;
uniform float z_near;
uniform bool enable_ssao;
// Depth-based shadow map (object-on-object and self shadows). shadow_intensity == 0 disables it.
uniform sampler2D shadow_map;
uniform mat4 shadow_light_vp;
uniform float shadow_intensity;
uniform float shadow_map_texel;
varying vec3 clipping_planes_dots;
varying float color_clip_plane_dot;
@@ -167,10 +173,39 @@ vec3 compute_window_reflection(vec3 normal, vec3 view_dir)
float intensity = window_light * bars * (0.15 + 0.15 * fresnel) * facing;
intensity = clamp(intensity, 0.0, 0.25);
return vec3(intensity);
}
// Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is
// occluded from the light in the shadow map. 3x3 PCF softens the edges.
float shadow_shade()
{
if (shadow_intensity <= 0.0)
return 1.0;
vec4 lp = shadow_light_vp * world_pos;
vec3 proj = lp.xyz / lp.w;
proj = proj * 0.5 + 0.5;
if (proj.z > 1.0)
return 1.0;
// Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This
// suppresses self-shadow acne without discarding real shadows cast by other objects onto
// back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow).
float NdotL = dot(normalize(eye_normal), LIGHT_TOP_DIR);
float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));
// 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne.
float sum = 0.0;
for (int x = -2; x <= 2; ++x) {
for (int y = -2; y <= 2; ++y) {
float closest = texture2D(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;
sum += (proj.z - bias > closest) ? 1.0 : 0.0;
}
}
return 1.0 - shadow_intensity * (sum / 25.0);
}
void main()
{
if (any(lessThan(clipping_planes_dots, ZERO)))
@@ -226,8 +261,10 @@ void main()
// SSAO is applied in post-process pass. Keep base lighting unchanged here.
float shade = shadow_shade();
if (is_outline) {
vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS;
vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade;
vec4 shaded_color = vec4(clamp(shaded_rgb, vec3(0.0), vec3(1.0)), color.a);
vec2 fragCoord = gl_FragCoord.xy;
float s = DetectSilho(fragCoord);
@@ -240,8 +277,8 @@ void main()
}
#ifdef ENABLE_ENVIRONMENT_MAP
else if (use_environment_tex)
gl_FragColor = vec4(clamp((0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + window_reflection + 0.8 * color.rgb * diffuse) * PHONG_BRIGHTNESS, vec3(0.0), vec3(1.0)), color.a);
gl_FragColor = vec4(clamp((0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + window_reflection + 0.8 * color.rgb * diffuse) * PHONG_BRIGHTNESS * shade, vec3(0.0), vec3(1.0)), color.a);
#endif
else
gl_FragColor = vec4(clamp((vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS, vec3(0.0), vec3(1.0)), color.a);
gl_FragColor = vec4(clamp((vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade, vec3(0.0), vec3(1.0)), color.a);
}

View File

@@ -0,0 +1,40 @@
#version 110
// Draws the build-plate as a receiver of the same depth shadow map used for object/self shadows,
// so the plate, objects, and self-shadows all come from one unified technique.
uniform sampler2D shadow_map;
uniform mat4 shadow_light_vp;
uniform float shadow_intensity;
uniform float shadow_map_texel;
varying vec4 world_pos;
// Fraction of the 5x5 PCF kernel occluded from the light. Matches the object shadow shader.
float shadow_occlusion()
{
vec4 lp = shadow_light_vp * world_pos;
vec3 proj = lp.xyz / lp.w;
proj = proj * 0.5 + 0.5;
if (proj.z > 1.0)
return 0.0;
// The plate is a pure receiver (never rendered into the shadow map), so a tiny constant
// bias for numerical safety is enough here.
float bias = 0.0004;
float sum = 0.0;
for (int x = -2; x <= 2; ++x) {
for (int y = -2; y <= 2; ++y) {
float closest = texture2D(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;
sum += (proj.z - bias > closest) ? 1.0 : 0.0;
}
}
return sum / 25.0;
}
void main()
{
float occ = shadow_occlusion();
if (occ <= 0.0)
discard;
gl_FragColor = vec4(0.0, 0.0, 0.0, shadow_intensity * occ);
}

View File

@@ -0,0 +1,16 @@
#version 110
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
attribute vec3 v_position;
// The plate mask quad is authored directly in world coordinates (z = 0 plane),
// so v_position is already the world position of the fragment.
varying vec4 world_pos;
void main()
{
world_pos = vec4(v_position, 1.0);
gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0);
}

View File

@@ -54,6 +54,15 @@ const float ONE_OVER_EPSILON = 1e4;
uniform float z_far;
uniform float z_near;
// Depth-based shadow map (object-on-object and self shadows). shadow_intensity == 0 disables it.
uniform sampler2D shadow_map;
uniform mat4 shadow_light_vp;
uniform float shadow_intensity;
uniform float shadow_map_texel;
// LIGHT_TOP_DIR in eye space (matches the diffuse light used for shading in gouraud.vs).
const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
in vec3 clipping_planes_dots;
in float color_clip_plane_dot;
@@ -129,6 +138,35 @@ float DetectSilho(vec2 fragCoord)
);
}
// Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is
// occluded from the light in the shadow map. 3x3 PCF softens the edges.
float shadow_shade()
{
if (shadow_intensity <= 0.0)
return 1.0;
vec4 lp = shadow_light_vp * world_pos;
vec3 proj = lp.xyz / lp.w;
proj = proj * 0.5 + 0.5;
if (proj.z > 1.0)
return 1.0;
// Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This
// suppresses self-shadow acne without discarding real shadows cast by other objects onto
// back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow).
float NdotL = dot(normalize(eye_normal), SHADOW_LIGHT_DIR);
float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));
// 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne.
float sum = 0.0;
for (int x = -2; x <= 2; ++x) {
for (int y = -2; y <= 2; ++y) {
float closest = texture(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;
sum += (proj.z - bias > closest) ? 1.0 : 0.0;
}
}
return 1.0 - shadow_intensity * (sum / 25.0);
}
out vec4 out_color;
void main()
@@ -181,10 +219,11 @@ void main()
bool is_out_printable_height = (all(greaterThan(eph_check_min, vec3(1.0))) && all(lessThan(eph_check_max, vec3(1.0))));
color.rgb = is_out_printable_height ? mix(color.rgb, ZERO, 0.7) : color.rgb;
}
float shade = shadow_shade();
//BBS: add outline_color
if (is_outline) {
color = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a);
color = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a);
vec2 fragCoord = gl_FragCoord.xy;
float s = DetectSilho(fragCoord);
// Makes silhouettes thicker.
@@ -192,13 +231,13 @@ void main()
{
s = max(s, DetectSilho(fragCoord.xy + vec2(i, 0)));
s = max(s, DetectSilho(fragCoord.xy + vec2(0, i)));
}
}
out_color = vec4(mix(color.rgb, getBackfaceColor(color.rgb), s), color.a);
}
#ifdef ENABLE_ENVIRONMENT_MAP
else if (use_environment_tex)
out_color = vec4(0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x, color.a);
out_color = vec4((0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color.rgb * intensity.x) * shade, color.a);
#endif
else
out_color = vec4(vec3(intensity.y) + color.rgb * intensity.x, color.a);
out_color = vec4((vec3(intensity.y) + color.rgb * intensity.x) * shade, color.a);
}

View File

@@ -65,6 +65,12 @@ uniform float z_far;
uniform float z_near;
uniform bool enable_ssao;
// Depth-based shadow map (object-on-object and self shadows). shadow_intensity == 0 disables it.
uniform sampler2D shadow_map;
uniform mat4 shadow_light_vp;
uniform float shadow_intensity;
uniform float shadow_map_texel;
in vec3 clipping_planes_dots;
in float color_clip_plane_dot;
@@ -170,11 +176,40 @@ vec3 compute_window_reflection(vec3 normal, vec3 view_dir)
float intensity = window_light * bars * (0.15 + 0.15 * fresnel) * facing;
intensity = clamp(intensity, 0.0, 0.25);
intensity = clamp(intensity, 0.0, 0.25);
return vec3(intensity);
}
// Returns a lighting multiplier in [1 - shadow_intensity, 1]: < 1 where the fragment is
// occluded from the light in the shadow map. 3x3 PCF softens the edges.
float shadow_shade()
{
if (shadow_intensity <= 0.0)
return 1.0;
vec4 lp = shadow_light_vp * world_pos;
vec3 proj = lp.xyz / lp.w;
proj = proj * 0.5 + 0.5;
if (proj.z > 1.0)
return 1.0;
// Slope-scaled depth bias: larger where the surface grazes / faces away from the light. This
// suppresses self-shadow acne without discarding real shadows cast by other objects onto
// back-facing surfaces (e.g. the shaded back/tip of a cone sitting inside a larger shadow).
float NdotL = dot(normalize(eye_normal), LIGHT_TOP_DIR);
float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));
// 5x5 PCF: softens shadow edges into a smooth penumbra and blurs residual facet acne.
float sum = 0.0;
for (int x = -2; x <= 2; ++x) {
for (int y = -2; y <= 2; ++y) {
float closest = texture(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;
sum += (proj.z - bias > closest) ? 1.0 : 0.0;
}
}
return 1.0 - shadow_intensity * (sum / 25.0);
}
void main()
{
if (any(lessThan(clipping_planes_dots, ZERO)))
@@ -230,8 +265,10 @@ void main()
// SSAO is applied in post-process pass. Keep base lighting unchanged here.
float shade = shadow_shade();
if (is_outline) {
vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS;
vec3 shaded_rgb = (vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade;
vec4 shaded_color = vec4(clamp(shaded_rgb, vec3(0.0), vec3(1.0)), color.a);
vec2 fragCoord = gl_FragCoord.xy;
float s = DetectSilho(fragCoord);
@@ -244,8 +281,8 @@ void main()
}
#ifdef ENABLE_ENVIRONMENT_MAP
else if (use_environment_tex)
out_color = vec4(clamp((0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + window_reflection + 0.8 * color.rgb * diffuse) * PHONG_BRIGHTNESS, vec3(0.0), vec3(1.0)), color.a);
out_color = vec4(clamp((0.45 * texture(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + window_reflection + 0.8 * color.rgb * diffuse) * PHONG_BRIGHTNESS * shade, vec3(0.0), vec3(1.0)), color.a);
#endif
else
out_color = vec4(clamp((vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS, vec3(0.0), vec3(1.0)), color.a);
out_color = vec4(clamp((vec3(specular) + window_reflection + color.rgb * diffuse) * PHONG_BRIGHTNESS * shade, vec3(0.0), vec3(1.0)), color.a);
}

View File

@@ -0,0 +1,42 @@
#version 140
// Draws the build-plate as a receiver of the same depth shadow map used for object/self shadows,
// so the plate, objects, and self-shadows all come from one unified technique.
uniform sampler2D shadow_map;
uniform mat4 shadow_light_vp;
uniform float shadow_intensity;
uniform float shadow_map_texel;
in vec4 world_pos;
out vec4 out_color;
// Fraction of the 5x5 PCF kernel occluded from the light. Matches the object shadow shader.
float shadow_occlusion()
{
vec4 lp = shadow_light_vp * world_pos;
vec3 proj = lp.xyz / lp.w;
proj = proj * 0.5 + 0.5;
if (proj.z > 1.0)
return 0.0;
// The plate is a pure receiver (never rendered into the shadow map), so a tiny constant
// bias for numerical safety is enough here.
float bias = 0.0004;
float sum = 0.0;
for (int x = -2; x <= 2; ++x) {
for (int y = -2; y <= 2; ++y) {
float closest = texture(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;
sum += (proj.z - bias > closest) ? 1.0 : 0.0;
}
}
return sum / 25.0;
}
void main()
{
float occ = shadow_occlusion();
if (occ <= 0.0)
discard;
out_color = vec4(0.0, 0.0, 0.0, shadow_intensity * occ);
}

View File

@@ -0,0 +1,16 @@
#version 140
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
in vec3 v_position;
// The plate mask quad is authored directly in world coordinates (z = 0 plane),
// so v_position is already the world position of the fragment.
out vec4 world_pos;
void main()
{
world_pos = vec4(v_position, 1.0);
gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0);
}