+ v3f dir;
+ v3_sub( pb, pa, dir );
+
+ v3f dir_inv;
+ dir_inv[0] = 1.0f/dir[0];
+ dir_inv[1] = 1.0f/dir[1];
+ dir_inv[2] = 1.0f/dir[2];
+
+ int hit = -1;
+ float min_t = 1.0f;
+
+ int idx;
+ while( bh_next( world.geo_bh, &it, region, &idx ) )
+ {
+ u32 *ptri = &world.scene_geo->arrindices[ idx*3 ];
+ v3f tri[3];
+
+ boxf box;
+ box_init_inf( box );
+
+ for( int j=0; j<3; j++ )
+ {
+ v3_copy( world.scene_geo->arrvertices[ptri[j]].co, tri[j] );
+ box_addpt( box, tri[j] );
+ }
+
+ v3_add( (v3f){ r, r, r}, box[1], box[1] );
+ v3_add( (v3f){-r,-r,-r}, box[0], box[0] );
+
+ if( !ray_aabb1( box, pa, dir_inv, 1.0f ) )
+ continue;
+
+ float t;
+ v3f n1;
+ if( spherecast_triangle( tri, pa, dir, r, &t, n1 ) )
+ {
+ if( t < min_t )
+ {
+ min_t = t;
+ hit = idx;
+ v3_copy( n1, n );
+ }
+ }
+ }
+
+ *t = min_t;
+ return hit;
+}
+
+VG_STATIC struct world_material *world_tri_index_material( u32 index )
+{
+ for( int i=1; i<world.material_count; i++ )
+ {
+ struct world_material *mat = &world.materials[i];
+
+ if( (index >= mat->sm_geo.vertex_start) &&
+ (index < mat->sm_geo.vertex_start+mat->sm_geo.vertex_count ) )
+ {
+ return mat;
+ }
+ }
+
+ /* error material */
+ return &world.materials[0];
+}
+
+VG_STATIC struct world_material *world_contact_material( rb_ct *ct )
+{
+ return world_tri_index_material( ct->element_id );
+}
+
+VG_STATIC struct world_material *ray_hit_material( ray_hit *hit )
+{
+ return world_tri_index_material( hit->tri[0] );