BlueGit

golden-age paperdoll-renderer

glTF alphaMode BLEND: blend over opaque surfaces in production and live (eyes behind the cornea; Tim t1016u/t1017u); GPU probe case blend-over

timfa Grok Bot · pushed by timfa

Authored 2026-11-07 · 6 days ago

Hash
fd8f667d2d0ac2a954b2ca419218ba578a6fc53b
Parent
b3077f3b
5 files changed +130 −4
src/fbx_scene.rs +1 −0
@@ -683,6 +683,7 @@ fn extract_mesh(
683 683 flat_normals: !mesh.vertex_normal.exists,
684 684 specular: 0.,
685 685 shiny: None,
686 blend: false,
686 687 });
687 688 }
688 689 }
@@ -683,6 +683,7 @@ fn extract_mesh(
683 flat_normals: !mesh.vertex_normal.exists,
683 flat_normals: !mesh.vertex_normal.exists,
684 specular: 0.,
684 specular: 0.,
685 shiny: None,
685 shiny: None,
686 blend: false,
686 });
687 });
687 }
688 }
688 }
689 }
src/i18n_table.rs +2 −0
@@ -825,4 +825,6 @@ pub const TABLE: &[(&str, &str)] = &[
825 825 ("voorste materiaal niet als texture × factor getekend: {surface_front:?}", "front material not drawn as texture × factor: {surface_front:?}"),
826 826 ("materiaal per primitive verwisseld: {surface_swap:?}", "material per primitive swapped: {surface_swap:?}"),
827 827 ("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}", "GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}"),
828 ("BLEND-laag niet over het ondoorzichtige oppervlak gemengd: {blend_over:?}", "BLEND layer not blended over the opaque surface: {blend_over:?}"),
829 ("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}, blend-over={blend_over:?}", "GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}, blend-over={blend_over:?}"),
828 830 ];
@@ -825,4 +825,6 @@ pub const TABLE: &[(&str, &str)] = &[
825 ("voorste materiaal niet als texture × factor getekend: {surface_front:?}", "front material not drawn as texture × factor: {surface_front:?}"),
825 ("voorste materiaal niet als texture × factor getekend: {surface_front:?}", "front material not drawn as texture × factor: {surface_front:?}"),
826 ("materiaal per primitive verwisseld: {surface_swap:?}", "material per primitive swapped: {surface_swap:?}"),
826 ("materiaal per primitive verwisseld: {surface_swap:?}", "material per primitive swapped: {surface_swap:?}"),
827 ("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}", "GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}"),
827 ("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}", "GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}"),
828 ("BLEND-laag niet over het ondoorzichtige oppervlak gemengd: {blend_over:?}", "BLEND layer not blended over the opaque surface: {blend_over:?}"),
829 ("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}, blend-over={blend_over:?}", "GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}, blend-over={blend_over:?}"),
828];
830];
src/preview.rs +6 −0
@@ -159,6 +159,8 @@ pub struct BodySurface {
159 159 /// the extension) and its strength texture (alpha copied into RGB).
160 160 pub specular: f32,
161 161 pub shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
162 /// glTF alphaMode BLEND: composited over the opaque surfaces (t1016u).
163 pub blend: bool,
162 164 }
163 165
164 166 #[derive(Debug, Clone)]
@@ -468,6 +470,7 @@ impl StaticAcc {
468 470 flat_normals,
469 471 specular: 0.,
470 472 shiny: None,
473 blend: false,
471 474 });
472 475 Ok(())
473 476 }
@@ -693,6 +696,7 @@ fn load_gltf_file_unguarded(path: &Path) -> Result<PreviewCharacter, String> {
693 696 cutoff: prim.cutoff,
694 697 specular: prim.specular,
695 698 shiny: prim.shiny,
699 blend: prim.blend,
696 700 });
697 701 }
698 702 }
@@ -809,6 +813,7 @@ struct GltfPrimitive {
809 813 cutoff: f32,
810 814 specular: f32,
811 815 shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
816 blend: bool,
812 817 flat_normals: bool,
813 818 }
814 819
@@ -915,6 +920,7 @@ fn read_gltf_primitive(
915 920 },
916 921 specular,
917 922 shiny,
923 blend: material.alpha_mode() == gltf::material::AlphaMode::Blend,
918 924 })
919 925 }
920 926
@@ -159,6 +159,8 @@ pub struct BodySurface {
159 /// the extension) and its strength texture (alpha copied into RGB).
159 /// the extension) and its strength texture (alpha copied into RGB).
160 pub specular: f32,
160 pub specular: f32,
161 pub shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
161 pub shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
162 /// glTF alphaMode BLEND: composited over the opaque surfaces (t1016u).
163 pub blend: bool,
162}
164}
163
165
164#[derive(Debug, Clone)]
166#[derive(Debug, Clone)]
@@ -468,6 +470,7 @@ impl StaticAcc {
468 flat_normals,
470 flat_normals,
469 specular: 0.,
471 specular: 0.,
470 shiny: None,
472 shiny: None,
473 blend: false,
471 });
474 });
472 Ok(())
475 Ok(())
473 }
476 }
@@ -693,6 +696,7 @@ fn load_gltf_file_unguarded(path: &Path) -> Result<PreviewCharacter, String> {
693 cutoff: prim.cutoff,
696 cutoff: prim.cutoff,
694 specular: prim.specular,
697 specular: prim.specular,
695 shiny: prim.shiny,
698 shiny: prim.shiny,
699 blend: prim.blend,
696 });
700 });
697 }
701 }
698 }
702 }
@@ -809,6 +813,7 @@ struct GltfPrimitive {
809 cutoff: f32,
813 cutoff: f32,
810 specular: f32,
814 specular: f32,
811 shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
815 shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
816 blend: bool,
812 flat_normals: bool,
817 flat_normals: bool,
813}
818}
814
819
@@ -915,6 +920,7 @@ fn read_gltf_primitive(
915 },
920 },
916 specular,
921 specular,
917 shiny,
922 shiny,
923 blend: material.alpha_mode() == gltf::material::AlphaMode::Blend,
918 })
924 })
919}
925}
920
926
src/preview_gl.rs +78 −3
@@ -319,6 +319,7 @@ fn body_frame(
319 319 cutoff: s.cutoff,
320 320 specular: s.specular,
321 321 shiny: s.shiny.clone(),
322 blend: s.blend,
322 323 })
323 324 .collect();
324 325 PendingFrame {
@@ -407,6 +408,8 @@ struct SurfaceDraw {
407 408 cutoff: f32,
408 409 specular: f32,
409 410 shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
411 /// glTF BLEND: drawn after the opaque ranges, blended, no depth write.
412 blend: bool,
410 413 }
411 414
412 415 impl PendingFrame {
@@ -582,7 +585,46 @@ impl GpuCache {
582 585 let albedo_enabled = gl.get_uniform_location(program, "u_albedo_enabled");
583 586 let shiny_enabled = gl.get_uniform_location(program, "u_shiny_enabled");
584 587 let specular = gl.get_uniform_location(program, "u_specular");
585 for (index, surface) in frame.surfaces.iter().enumerate() {
588 // glTF BLEND (design.md t1016u): opaque first, then BLEND blended
589 // without depth writes, then BLEND depth only.
590 let order: Vec<(usize, &SurfaceDraw, u8)> = (0..3u8)
591 .flat_map(|pass| {
592 frame
593 .surfaces
594 .iter()
595 .enumerate()
596 .filter(move |(_, s)| s.blend == (pass > 0))
597 .map(move |(i, s)| (i, s, pass))
598 })
599 .collect();
600 for (index, surface, pass) in order {
601 match pass {
602 0 => {
603 gl.disable(glow::BLEND);
604 gl.depth_mask(true);
605 gl.color_mask(true, true, true, true);
606 }
607 1 => {
608 gl.enable(glow::BLEND);
609 gl.blend_func_separate(
610 glow::SRC_ALPHA,
611 glow::ONE_MINUS_SRC_ALPHA,
612 glow::ZERO,
613 glow::ONE,
614 );
615 gl.depth_mask(false);
616 gl.color_mask(true, true, true, true);
617 }
618 _ => {
619 gl.disable(glow::BLEND);
620 gl.depth_mask(true);
621 gl.color_mask(false, false, false, false);
622 }
623 }
624 gl.uniform_1_i32(
625 gl.get_uniform_location(program, "u_blend").as_ref(),
626 i32::from(pass == 1),
627 );
586 628 let end = (surface.first + surface.count).min(self.index_count as usize);
587 629 if surface.first >= end {
588 630 continue;
@@ -612,6 +654,10 @@ impl GpuCache {
612 654 (surface.first * 4) as i32,
613 655 );
614 656 }
657 gl.disable(glow::BLEND);
658 gl.depth_mask(true);
659 gl.color_mask(true, true, true, true);
660 gl.uniform_1_i32(gl.get_uniform_location(program, "u_blend").as_ref(), 0);
615 661 }
616 662 gl.bind_vertex_array(None);
617 663 while self.layers.len() > frame.equipment.len() {
@@ -865,6 +911,7 @@ uniform vec3 u_eye;
865 911 in vec2 v_uv;
866 912 in vec3 v_world;
867 913 out vec4 frag;
914 uniform bool u_blend;
868 915 void main() {
869 916 vec3 n = normalize(v_normal);
870 917 vec3 light = normalize(vec3(0.35, 0.85, 0.4));
@@ -875,7 +922,7 @@ void main() {
875 922 float strength=u_specular;
876 923 if(u_shiny_enabled) strength*=dot(texture(u_shiny,v_uv).rgb,vec3(0.2126,0.7152,0.0722));
877 924 float highlight=pow(max(dot(reflect(-light,n),normalize(u_eye-v_world)),0.0),32.0)*strength;
878 frag = vec4(clamp(color.rgb * shade + highlight,0.0,1.0), 1.0);
925 frag = vec4(clamp(color.rgb * shade + highlight,0.0,1.0), u_blend ? color.a : 1.0);
879 926 }
880 927 "#;
881 928
@@ -1108,6 +1155,7 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1108 1155 cutoff: 0.001,
1109 1156 specular: 0.,
1110 1157 shiny: None,
1158 blend: false,
1111 1159 },
1112 1160 SurfaceDraw {
1113 1161 first: 3,
@@ -1117,6 +1165,7 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1117 1165 cutoff: 0.001,
1118 1166 specular: 0.,
1119 1167 shiny: None,
1168 blend: false,
1120 1169 },
1121 1170 ];
1122 1171 cache.pending = Some(body.clone());
@@ -1165,6 +1214,7 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1165 1214 cutoff: 0.001,
1166 1215 specular: 0.,
1167 1216 shiny: None,
1217 blend: false,
1168 1218 }];
1169 1219 cache.pending = Some(body);
1170 1220 cache.paint(gl, &info, true);
@@ -1187,7 +1237,32 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1187 1237 "equipment-UV verkeerd georiënteerd: {equipment_uv:?}"
1188 1238 ));
1189 1239 }
1190 println!("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}");
1240 // glTF BLEND (Tim t1016u): a nearly transparent front layer listed
1241 // first (the cornea) must not hide the opaque surface behind it.
1242 let mut body = make_frame(vec![0, 1, 2, 3, 4, 5], 17);
1243 let plain = |first, color: [f32; 4], blend| SurfaceDraw {
1244 first,
1245 count: 3,
1246 color,
1247 albedo: None,
1248 cutoff: 0.001,
1249 specular: 0.,
1250 shiny: None,
1251 blend,
1252 };
1253 body.surfaces = vec![
1254 plain(0, [1., 1., 1., 0.1], true),
1255 plain(3, [1., 0., 0., 1.], false),
1256 ];
1257 cache.pending = Some(body);
1258 cache.paint(gl, &info, true);
1259 let blend_over = read();
1260 if blend_over[1] < 5 || blend_over[1] > 60 || blend_over[0] < 2 * blend_over[1] {
1261 return Err(format!(
1262 "BLEND-laag niet over het ondoorzichtige oppervlak gemengd: {blend_over:?}"
1263 ));
1264 }
1265 println!("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}, blend-over={blend_over:?}");
1191 1266 Ok(())
1192 1267 })();
1193 1268 cache.destroy(gl);
@@ -319,6 +319,7 @@ fn body_frame(
319 cutoff: s.cutoff,
319 cutoff: s.cutoff,
320 specular: s.specular,
320 specular: s.specular,
321 shiny: s.shiny.clone(),
321 shiny: s.shiny.clone(),
322 blend: s.blend,
322 })
323 })
323 .collect();
324 .collect();
324 PendingFrame {
325 PendingFrame {
@@ -407,6 +408,8 @@ struct SurfaceDraw {
407 cutoff: f32,
408 cutoff: f32,
408 specular: f32,
409 specular: f32,
409 shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
410 shiny: Option<std::sync::Arc<crate::equipment::Texture>>,
411 /// glTF BLEND: drawn after the opaque ranges, blended, no depth write.
412 blend: bool,
410}
413}
411
414
412impl PendingFrame {
415impl PendingFrame {
@@ -582,7 +585,46 @@ impl GpuCache {
582 let albedo_enabled = gl.get_uniform_location(program, "u_albedo_enabled");
585 let albedo_enabled = gl.get_uniform_location(program, "u_albedo_enabled");
583 let shiny_enabled = gl.get_uniform_location(program, "u_shiny_enabled");
586 let shiny_enabled = gl.get_uniform_location(program, "u_shiny_enabled");
584 let specular = gl.get_uniform_location(program, "u_specular");
587 let specular = gl.get_uniform_location(program, "u_specular");
585 for (index, surface) in frame.surfaces.iter().enumerate() {
588 // glTF BLEND (design.md t1016u): opaque first, then BLEND blended
589 // without depth writes, then BLEND depth only.
590 let order: Vec<(usize, &SurfaceDraw, u8)> = (0..3u8)
591 .flat_map(|pass| {
592 frame
593 .surfaces
594 .iter()
595 .enumerate()
596 .filter(move |(_, s)| s.blend == (pass > 0))
597 .map(move |(i, s)| (i, s, pass))
598 })
599 .collect();
600 for (index, surface, pass) in order {
601 match pass {
602 0 => {
603 gl.disable(glow::BLEND);
604 gl.depth_mask(true);
605 gl.color_mask(true, true, true, true);
606 }
607 1 => {
608 gl.enable(glow::BLEND);
609 gl.blend_func_separate(
610 glow::SRC_ALPHA,
611 glow::ONE_MINUS_SRC_ALPHA,
612 glow::ZERO,
613 glow::ONE,
614 );
615 gl.depth_mask(false);
616 gl.color_mask(true, true, true, true);
617 }
618 _ => {
619 gl.disable(glow::BLEND);
620 gl.depth_mask(true);
621 gl.color_mask(false, false, false, false);
622 }
623 }
624 gl.uniform_1_i32(
625 gl.get_uniform_location(program, "u_blend").as_ref(),
626 i32::from(pass == 1),
627 );
586 let end = (surface.first + surface.count).min(self.index_count as usize);
628 let end = (surface.first + surface.count).min(self.index_count as usize);
587 if surface.first >= end {
629 if surface.first >= end {
588 continue;
630 continue;
@@ -612,6 +654,10 @@ impl GpuCache {
612 (surface.first * 4) as i32,
654 (surface.first * 4) as i32,
613 );
655 );
614 }
656 }
657 gl.disable(glow::BLEND);
658 gl.depth_mask(true);
659 gl.color_mask(true, true, true, true);
660 gl.uniform_1_i32(gl.get_uniform_location(program, "u_blend").as_ref(), 0);
615 }
661 }
616 gl.bind_vertex_array(None);
662 gl.bind_vertex_array(None);
617 while self.layers.len() > frame.equipment.len() {
663 while self.layers.len() > frame.equipment.len() {
@@ -865,6 +911,7 @@ uniform vec3 u_eye;
865in vec2 v_uv;
911in vec2 v_uv;
866in vec3 v_world;
912in vec3 v_world;
867out vec4 frag;
913out vec4 frag;
914uniform bool u_blend;
868void main() {
915void main() {
869 vec3 n = normalize(v_normal);
916 vec3 n = normalize(v_normal);
870 vec3 light = normalize(vec3(0.35, 0.85, 0.4));
917 vec3 light = normalize(vec3(0.35, 0.85, 0.4));
@@ -875,7 +922,7 @@ void main() {
875 float strength=u_specular;
922 float strength=u_specular;
876 if(u_shiny_enabled) strength*=dot(texture(u_shiny,v_uv).rgb,vec3(0.2126,0.7152,0.0722));
923 if(u_shiny_enabled) strength*=dot(texture(u_shiny,v_uv).rgb,vec3(0.2126,0.7152,0.0722));
877 float highlight=pow(max(dot(reflect(-light,n),normalize(u_eye-v_world)),0.0),32.0)*strength;
924 float highlight=pow(max(dot(reflect(-light,n),normalize(u_eye-v_world)),0.0),32.0)*strength;
878 frag = vec4(clamp(color.rgb * shade + highlight,0.0,1.0), 1.0);
925 frag = vec4(clamp(color.rgb * shade + highlight,0.0,1.0), u_blend ? color.a : 1.0);
879}
926}
880"#;
927"#;
881
928
@@ -1108,6 +1155,7 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1108 cutoff: 0.001,
1155 cutoff: 0.001,
1109 specular: 0.,
1156 specular: 0.,
1110 shiny: None,
1157 shiny: None,
1158 blend: false,
1111 },
1159 },
1112 SurfaceDraw {
1160 SurfaceDraw {
1113 first: 3,
1161 first: 3,
@@ -1117,6 +1165,7 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1117 cutoff: 0.001,
1165 cutoff: 0.001,
1118 specular: 0.,
1166 specular: 0.,
1119 shiny: None,
1167 shiny: None,
1168 blend: false,
1120 },
1169 },
1121 ];
1170 ];
1122 cache.pending = Some(body.clone());
1171 cache.pending = Some(body.clone());
@@ -1165,6 +1214,7 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1165 cutoff: 0.001,
1214 cutoff: 0.001,
1166 specular: 0.,
1215 specular: 0.,
1167 shiny: None,
1216 shiny: None,
1217 blend: false,
1168 }];
1218 }];
1169 cache.pending = Some(body);
1219 cache.pending = Some(body);
1170 cache.paint(gl, &info, true);
1220 cache.paint(gl, &info, true);
@@ -1187,7 +1237,32 @@ pub unsafe fn depth_regression_probe(gl: &glow::Context) -> Result<(), String> {
1187 "equipment-UV verkeerd georiënteerd: {equipment_uv:?}"
1237 "equipment-UV verkeerd georiënteerd: {equipment_uv:?}"
1188 ));
1238 ));
1189 }
1239 }
1190 println!("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}");
1240 // glTF BLEND (Tim t1016u): a nearly transparent front layer listed
1241 // first (the cornea) must not hide the opaque surface behind it.
1242 let mut body = make_frame(vec![0, 1, 2, 3, 4, 5], 17);
1243 let plain = |first, color: [f32; 4], blend| SurfaceDraw {
1244 first,
1245 count: 3,
1246 color,
1247 albedo: None,
1248 cutoff: 0.001,
1249 specular: 0.,
1250 shiny: None,
1251 blend,
1252 };
1253 body.surfaces = vec![
1254 plain(0, [1., 1., 1., 0.1], true),
1255 plain(3, [1., 0., 0., 1.], false),
1256 ];
1257 cache.pending = Some(body);
1258 cache.paint(gl, &info, true);
1259 let blend_over = read();
1260 if blend_over[1] < 5 || blend_over[1] > 60 || blend_over[0] < 2 * blend_over[1] {
1261 return Err(format!(
1262 "BLEND-laag niet over het ondoorzichtige oppervlak gemengd: {blend_over:?}"
1263 ));
1264 }
1265 println!("GPU depth PASS: native {native_bits}-bit, front={near:?}, next-frame={next:?}, reversed={reverse:?}, behind-layer={hidden:?}, textured-front={textured:?}, alpha-cutout={cutout:?}, shiny={shiny:?}, matte={matte:?}, body-surface texture×factor={surface_front:?}, body-surface factor-only={surface_swap:?}, body-uv-top={body_uv:?}, equipment-uv-bottom={equipment_uv:?}, blend-over={blend_over:?}");
1191 Ok(())
1266 Ok(())
1192 })();
1267 })();
1193 cache.destroy(gl);
1268 cache.destroy(gl);
src/production.rs +43 −1
@@ -40,6 +40,8 @@ pub struct Draw {
40 40 pub specular: f32,
41 41 pub cutoff: f32,
42 42 pub flat_normals: bool,
43 /// glTF BLEND: drawn after the opaque draws, blended (design.md t1016u).
44 pub blend: bool,
43 45 }
44 46 #[derive(Clone)]
45 47 pub struct Scene {
@@ -312,6 +314,7 @@ pub fn scene(
312 314 specular: layer.specular,
313 315 cutoff: 0.5,
314 316 flat_normals: false,
317 blend: false,
315 318 });
316 319 }
317 320 } else {
@@ -353,6 +356,7 @@ pub fn scene(
353 356 specular: 0.,
354 357 cutoff: 0.001,
355 358 flat_normals: !body.source_normals_complete,
359 blend: false,
356 360 });
357 361 } else {
358 362 for surface in &body.surfaces {
@@ -368,6 +372,7 @@ pub fn scene(
368 372 specular: surface.specular,
369 373 cutoff: surface.cutoff,
370 374 flat_normals: surface.flat_normals,
375 blend: surface.blend,
371 376 });
372 377 }
373 378 }
@@ -645,7 +650,40 @@ impl GpuRenderer {
645 650 gl.enable_vertex_attrib_array(slot);
646 651 gl.vertex_attrib_pointer_f32(slot, size, glow::FLOAT, false, 12 * 4, offset * 4);
647 652 }
648 for draw in &scene.draws {
653 // glTF BLEND (design.md t1016u): opaque/mask first, then the
654 // BLEND draws blended without depth writes, then their depth only.
655 let order: Vec<(&Draw, u8)> = scene
656 .draws
657 .iter()
658 .filter(|d| !d.blend)
659 .map(|d| (d, 0))
660 .chain(scene.draws.iter().filter(|d| d.blend).map(|d| (d, 1)))
661 .chain(scene.draws.iter().filter(|d| d.blend).map(|d| (d, 2)))
662 .collect();
663 for (draw, pass) in order {
664 match pass {
665 0 => {
666 gl.disable(glow::BLEND);
667 gl.depth_mask(true);
668 gl.color_mask(true, true, true, true);
669 }
670 1 => {
671 gl.enable(glow::BLEND);
672 gl.blend_func_separate(
673 glow::SRC_ALPHA,
674 glow::ONE_MINUS_SRC_ALPHA,
675 glow::ONE,
676 glow::ONE_MINUS_SRC_ALPHA,
677 );
678 gl.depth_mask(false);
679 gl.color_mask(true, true, true, true);
680 }
681 _ => {
682 gl.disable(glow::BLEND);
683 gl.depth_mask(true);
684 gl.color_mask(false, false, false, false);
685 }
686 }
649 687 if draw.positions.len() != draw.normals.len()
650 688 || draw
651 689 .indices
@@ -756,6 +794,9 @@ impl GpuRenderer {
756 794 gl.delete_texture(t);
757 795 }
758 796 }
797 gl.disable(glow::BLEND);
798 gl.depth_mask(true);
799 gl.color_mask(true, true, true, true);
759 800 let pixels = scene.width as usize * scene.height as usize;
760 801 let mut maps = Vec::new();
761 802 gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1);
@@ -1936,6 +1977,7 @@ pub unsafe fn map_regression_probe(gl: &glow::Context) -> Result<(), String> {
1936 1977 specular,
1937 1978 cutoff: 0.001,
1938 1979 flat_normals: false,
1980 blend: false,
1939 1981 };
1940 1982 let mut renderer = GpuRenderer::default();
1941 1983 let mut scene = Scene {
@@ -40,6 +40,8 @@ pub struct Draw {
40 pub specular: f32,
40 pub specular: f32,
41 pub cutoff: f32,
41 pub cutoff: f32,
42 pub flat_normals: bool,
42 pub flat_normals: bool,
43 /// glTF BLEND: drawn after the opaque draws, blended (design.md t1016u).
44 pub blend: bool,
43}
45}
44#[derive(Clone)]
46#[derive(Clone)]
45pub struct Scene {
47pub struct Scene {
@@ -312,6 +314,7 @@ pub fn scene(
312 specular: layer.specular,
314 specular: layer.specular,
313 cutoff: 0.5,
315 cutoff: 0.5,
314 flat_normals: false,
316 flat_normals: false,
317 blend: false,
315 });
318 });
316 }
319 }
317 } else {
320 } else {
@@ -353,6 +356,7 @@ pub fn scene(
353 specular: 0.,
356 specular: 0.,
354 cutoff: 0.001,
357 cutoff: 0.001,
355 flat_normals: !body.source_normals_complete,
358 flat_normals: !body.source_normals_complete,
359 blend: false,
356 });
360 });
357 } else {
361 } else {
358 for surface in &body.surfaces {
362 for surface in &body.surfaces {
@@ -368,6 +372,7 @@ pub fn scene(
368 specular: surface.specular,
372 specular: surface.specular,
369 cutoff: surface.cutoff,
373 cutoff: surface.cutoff,
370 flat_normals: surface.flat_normals,
374 flat_normals: surface.flat_normals,
375 blend: surface.blend,
371 });
376 });
372 }
377 }
373 }
378 }
@@ -645,7 +650,40 @@ impl GpuRenderer {
645 gl.enable_vertex_attrib_array(slot);
650 gl.enable_vertex_attrib_array(slot);
646 gl.vertex_attrib_pointer_f32(slot, size, glow::FLOAT, false, 12 * 4, offset * 4);
651 gl.vertex_attrib_pointer_f32(slot, size, glow::FLOAT, false, 12 * 4, offset * 4);
647 }
652 }
648 for draw in &scene.draws {
653 // glTF BLEND (design.md t1016u): opaque/mask first, then the
654 // BLEND draws blended without depth writes, then their depth only.
655 let order: Vec<(&Draw, u8)> = scene
656 .draws
657 .iter()
658 .filter(|d| !d.blend)
659 .map(|d| (d, 0))
660 .chain(scene.draws.iter().filter(|d| d.blend).map(|d| (d, 1)))
661 .chain(scene.draws.iter().filter(|d| d.blend).map(|d| (d, 2)))
662 .collect();
663 for (draw, pass) in order {
664 match pass {
665 0 => {
666 gl.disable(glow::BLEND);
667 gl.depth_mask(true);
668 gl.color_mask(true, true, true, true);
669 }
670 1 => {
671 gl.enable(glow::BLEND);
672 gl.blend_func_separate(
673 glow::SRC_ALPHA,
674 glow::ONE_MINUS_SRC_ALPHA,
675 glow::ONE,
676 glow::ONE_MINUS_SRC_ALPHA,
677 );
678 gl.depth_mask(false);
679 gl.color_mask(true, true, true, true);
680 }
681 _ => {
682 gl.disable(glow::BLEND);
683 gl.depth_mask(true);
684 gl.color_mask(false, false, false, false);
685 }
686 }
649 if draw.positions.len() != draw.normals.len()
687 if draw.positions.len() != draw.normals.len()
650 || draw
688 || draw
651 .indices
689 .indices
@@ -756,6 +794,9 @@ impl GpuRenderer {
756 gl.delete_texture(t);
794 gl.delete_texture(t);
757 }
795 }
758 }
796 }
797 gl.disable(glow::BLEND);
798 gl.depth_mask(true);
799 gl.color_mask(true, true, true, true);
759 let pixels = scene.width as usize * scene.height as usize;
800 let pixels = scene.width as usize * scene.height as usize;
760 let mut maps = Vec::new();
801 let mut maps = Vec::new();
761 gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1);
802 gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1);
@@ -1936,6 +1977,7 @@ pub unsafe fn map_regression_probe(gl: &glow::Context) -> Result<(), String> {
1936 specular,
1977 specular,
1937 cutoff: 0.001,
1978 cutoff: 0.001,
1938 flat_normals: false,
1979 flat_normals: false,
1980 blend: false,
1939 };
1981 };
1940 let mut renderer = GpuRenderer::default();
1982 let mut renderer = GpuRenderer::default();
1941 let mut scene = Scene {
1983 let mut scene = Scene {