Skip to content

Commit

Permalink
#412 Fix ray intersect on Firefox
Browse files Browse the repository at this point in the history
  • Loading branch information
asny committed Feb 23, 2024
1 parent d5b040f commit 5d52c48
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 17 deletions.
43 changes: 31 additions & 12 deletions src/core/render_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,31 +125,50 @@ impl<'a> RenderTarget<'a> {

///
/// Returns the colors of the pixels in this render target.
/// The number of channels per pixel and the data format for each channel is specified by the generic parameter.
/// The number of channels per pixel and the data format for each channel returned from this function is specified by the generic parameter `T`.
///
/// **Note:** On web, the data format needs to match the data format of the color texture.
/// **Note:**
/// The base type of the generic parameter `T` must match the base type of the render target, for example if the render targets base type is `u8`, the base type of `T` must also be `u8`.
///
/// **Web:**
/// The generic parameter `T` is limited to:
/// - Unsigned byte RGBA (Specify `T` as either `Vec4<u8>` or `[u8; 4]`) which works with any render target using `u8` as its base type.
/// - 32-bit float RGBA (Specify `T` as either `Vec4<f32>` or `[f32; 4]`) which works with any render target using `f16` or `f32` as its base type.
///
pub fn read_color<T: TextureDataType>(&self) -> Vec<T> {
self.read_color_partially(self.scissor_box())
}

///
/// Returns the colors of the pixels in this render target inside the given scissor box.
/// The number of channels per pixel and the data format for each channel is specified by the generic parameter.
/// The number of channels per pixel and the data format for each channel returned from this function is specified by the generic parameter `T`.
///
/// **Note:**
/// The base type of the generic parameter `T` must match the base type of the render target, for example if the render targets base type is `u8`, the base type of `T` must also be `u8`.
///
/// **Note:** On web, the data format needs to match the data format of the color texture.
/// **Web:**
/// The generic parameter `T` is limited to:
/// - Unsigned byte RGBA (Specify `T` as either `Vec4<u8>` or `[u8; 4]`) which works with any render target using `u8` as its base type.
/// - 32-bit float RGBA (Specify `T` as either `Vec4<f32>` or `[f32; 4]`) which works with any render target using `f16` or `f32` as its base type.
///
pub fn read_color_partially<T: TextureDataType>(&self, scissor_box: ScissorBox) -> Vec<T> {
if self.id.is_some() && self.color.is_none() {
panic!("cannot read color from a render target without a color target");
panic!("Cannot read color from a render target without a color target");
}
let format = format_from_data_type::<T>();
let data_type = T::data_type();

// On web, the read format needs to be RGBA and f16 is not supported (see https://webglfundamentals.org/webgl/lessons/webgl-readpixels.html).
#[cfg(target_arch = "wasm32")]
if format != crate::context::RGBA
|| !(data_type == crate::context::UNSIGNED_BYTE || data_type == crate::context::FLOAT)
{
panic!("Only the texture data types `Vec4<T>` and `[T; 4]` where `T` is either `u8` or `f32` are supported when reading color from a render target on web.");
}

self.bind(crate::context::DRAW_FRAMEBUFFER);
self.bind(crate::context::READ_FRAMEBUFFER);
let mut data_size = std::mem::size_of::<T>();
// On web, the format needs to be RGBA if the data type is byte.
if data_size / T::size() as usize == 1 {
data_size *= 4 / T::size() as usize
}
let data_size = std::mem::size_of::<T>();
let mut bytes =
vec![0u8; scissor_box.width as usize * scissor_box.height as usize * data_size];
unsafe {
Expand All @@ -158,8 +177,8 @@ impl<'a> RenderTarget<'a> {
scissor_box.y,
scissor_box.width as i32,
scissor_box.height as i32,
format_from_data_type::<T>(),
T::data_type(),
format,
data_type,
crate::context::PixelPackData::Slice(&mut bytes),
);
}
Expand Down
20 changes: 16 additions & 4 deletions src/core/render_target/color_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,31 @@ impl<'a> ColorTarget<'a> {

///
/// Returns the colors of the pixels in this color target.
/// The number of channels per pixel and the data format for each channel is specified by the generic parameter.
/// The number of channels per pixel and the data format for each channel returned from this function is specified by the generic parameter `T`.
///
/// **Note:** On web, the data format needs to match the data format of the color texture.
/// **Note:**
/// The base type of the generic parameter `T` must match the base type of the color target, for example if the color targets base type is `u8`, the base type of `T` must also be `u8`.
///
/// **Web:**
/// The generic parameter `T` is limited to:
/// - Unsigned byte RGBA (Specify `T` as either `Vec4<u8>` or `[u8; 4]`) which works with any color target using `u8` as its base type.
/// - 32-bit float RGBA (Specify `T` as either `Vec4<f32>` or `[f32; 4]`) which works with any color target using `f16` or `f32` as its base type.
///
pub fn read<T: TextureDataType>(&self) -> Vec<T> {
self.read_partially(self.scissor_box())
}

///
/// Returns the colors of the pixels in this color target inside the given scissor box.
/// The number of channels per pixel and the data format for each channel is specified by the generic parameter.
/// The number of channels per pixel and the data format for each channel returned from this function is specified by the generic parameter `T`.
///
/// **Note:**
/// The base type of the generic parameter `T` must match the base type of the color target, for example if the color targets base type is `u8`, the base type of `T` must also be `u8`.
///
/// **Note:** On web, the data format needs to match the data format of the color texture.
/// **Web:**
/// The generic parameter `T` is limited to:
/// - Unsigned byte RGBA (Specify `T` as either `Vec4<u8>` or `[u8; 4]`) which works with any color target using `u8` as its base type.
/// - 32-bit float RGBA (Specify `T` as either `Vec4<f32>` or `[f32; 4]`) which works with any color target using `f16` or `f32` as its base type.
///
pub fn read_partially<T: TextureDataType>(&self, scissor_box: ScissorBox) -> Vec<T> {
self.as_render_target().read_color_partially(scissor_box)
Expand Down
2 changes: 1 addition & 1 deletion src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ pub fn ray_intersect(
render_with_material(context, &camera, &geometry, &depth_material, &[]);
}
})
.read_color()[0];
.read_color::<[f32; 4]>()[0][0];
if depth < 1.0 {
Some(position + direction * depth * max_depth)
} else {
Expand Down

0 comments on commit 5d52c48

Please sign in to comment.