@@ -618,15 +618,12 @@ __device__ void shade_material(int bounce, int sample_index, int buffer_size) {
618618
619619 normal = normalize (normal);
620620
621- // Make sure the normal is always pointing outwards
622- bool entering_material = dot (ray_direction, normal) < 0 .0f ;
623- if (!entering_material) {
624- normal = -normal;
625- }
621+ float mesh_scale_inv = 1 .0f / mesh_get_scale (hit.mesh_id );
626622
627623 // Load and propagate Ray Cone
628624 float cone_angle;
629625 float cone_width;
626+ float curvature = 0 .0f ;
630627 if (config.enable_mipmapping ) {
631628 if (bounce == 0 ) {
632629 cone_angle = camera.pixel_spread_angle ;
@@ -635,6 +632,30 @@ __device__ void shade_material(int bounce, int sample_index, int buffer_size) {
635632 cone_angle = material_buffer.buffer ->cone_angle [index];
636633 cone_width = material_buffer.buffer ->cone_width [index] + cone_angle * hit.t ;
637634 }
635+
636+ // Calculate Triangle curvature here,
637+ // not yet needed (see below) but after this step the Triangle position edges are transformed into world space
638+ curvature = triangle_get_curvature (
639+ hit_triangle.position_edge_1 ,
640+ hit_triangle.position_edge_2 ,
641+ hit_triangle.normal_edge_1 ,
642+ hit_triangle.normal_edge_2
643+ ) * mesh_scale_inv;
644+ }
645+
646+ matrix3x4_transform_direction (world, hit_triangle.position_edge_1 );
647+ matrix3x4_transform_direction (world, hit_triangle.position_edge_2 );
648+
649+ // Calculate geometric normal (in world space) to the Triangle
650+ float3 geometric_normal = cross (hit_triangle.position_edge_1 , hit_triangle.position_edge_2 );
651+ float triangle_double_area_inv = 1 .0f / length (geometric_normal);
652+ geometric_normal *= triangle_double_area_inv; // Normalize
653+
654+ // Check which side of the Triangle we are on based on its geometric normal
655+ bool entering_material = dot (ray_direction, geometric_normal) < 0 .0f ;
656+ if (!entering_material) {
657+ normal = -normal;
658+ curvature = -curvature;
638659 }
639660
640661 // Construct TBN frame
@@ -643,6 +664,8 @@ __device__ void shade_material(int bounce, int sample_index, int buffer_size) {
643664
644665 float3 omega_i = world_to_local (-ray_direction, tangent, bitangent, normal);
645666
667+ if (omega_i.z <= 0 .0f ) return ; // Below hemisphere, reject
668+
646669 // Initialize BSDF
647670 int material_id = mesh_get_material_id (hit.mesh_id );
648671
@@ -656,37 +679,21 @@ __device__ void shade_material(int bounce, int sample_index, int buffer_size) {
656679 bsdf.omega_i = omega_i;
657680 bsdf.init (bounce, entering_material, material_id);
658681
659- // Calculate texture level of detail
660- float mesh_scale = mesh_get_scale (hit.mesh_id );
661-
662- // Calculate geometric normal to the triangle.
663- // NOTE: geometric normal is kept in local space since ray_cone_get_texture_gradients() requires this,
664- // it is only later transformed into world space
665- float3 geometric_normal = cross (hit_triangle.position_edge_1 , hit_triangle.position_edge_2 );
666- float triangle_area_inv = 1 .0f / length (geometric_normal);
667- geometric_normal *= triangle_area_inv; // Normalize
668-
669682 if (BSDF::HAS_ALBEDO) {
670683 TextureLOD lod;
671684
672685 if (config.enable_mipmapping && bsdf.has_texture ()) {
673686 if (use_anisotropic_texture_sampling (bounce)) {
674- float3 ellipse_axis_1, ellipse_axis_2;
675- ray_cone_get_ellipse_axes (ray_direction, normal, cone_width, ellipse_axis_1, ellipse_axis_2);
676-
677- ray_cone_get_texture_gradients (
678- mesh_scale,
679- geometric_normal,
680- triangle_area_inv,
681- hit_triangle.position_0 , hit_triangle.position_edge_1 , hit_triangle.position_edge_2 ,
682- hit_triangle.tex_coord_0 , hit_triangle.tex_coord_edge_1 , hit_triangle.tex_coord_edge_2 ,
683- hit_point_local, tex_coord,
684- ellipse_axis_1, ellipse_axis_2,
685- lod.aniso .gradient_1 , lod.aniso .gradient_2
686- );
687+ float3 ellipse_axis_1;
688+ float3 ellipse_axis_2;
689+ ray_cone_get_ellipse_axes (ray_direction, geometric_normal, cone_width, ellipse_axis_1, ellipse_axis_2);
690+
691+ lod.aniso .gradient_1 = ray_cone_ellipse_axis_to_gradient (hit_triangle, triangle_double_area_inv, geometric_normal, hit_point, tex_coord, ellipse_axis_1);
692+ lod.aniso .gradient_2 = ray_cone_ellipse_axis_to_gradient (hit_triangle, triangle_double_area_inv, geometric_normal, hit_point, tex_coord, ellipse_axis_2);
687693 } else {
688- float lod_triangle = sqrtf (triangle_get_lod (mesh_scale, triangle_area_inv, hit_triangle.tex_coord_edge_1 , hit_triangle.tex_coord_edge_2 ));
689- float lod_ray_cone = ray_cone_get_lod (ray_direction, normal, cone_width);
694+ float lod_triangle = triangle_get_lod (triangle_double_area_inv, hit_triangle.tex_coord_edge_1 , hit_triangle.tex_coord_edge_2 );
695+ float lod_ray_cone = ray_cone_get_lod (ray_direction, geometric_normal, cone_width);
696+
690697 lod.iso .lod = log2f (lod_triangle * lod_ray_cone);
691698 }
692699 }
@@ -701,18 +708,8 @@ __device__ void shade_material(int bounce, int sample_index, int buffer_size) {
701708 aov_framebuffer_set (AOVType::POSITION, pixel_index, make_float4 (hit_point));
702709 }
703710
704- matrix3x4_transform_direction (world, geometric_normal);
705- geometric_normal = normalize (geometric_normal);
706-
707- // Calulate new Ray Cone angle based on Mesh curvature
711+ // Calulate new Ray Cone angle
708712 if (config.enable_mipmapping ) {
709- float curvature = triangle_get_curvature (
710- hit_triangle.position_edge_1 ,
711- hit_triangle.position_edge_2 ,
712- hit_triangle.normal_edge_1 ,
713- hit_triangle.normal_edge_2
714- ) / mesh_scale;
715-
716713 cone_angle -= 2 .0f * curvature * fabsf (cone_width) / dot (normal, ray_direction); // Eq. 5 (Akenine-Möller 2021)
717714 }
718715
0 commit comments