Add transmission, thickness and diffuse transmission textures

This commit is contained in:
Marco Buono 2023-04-16 12:20:16 -03:00
parent 08e7416b7f
commit 272b696d78
4 changed files with 99 additions and 3 deletions

View file

@ -157,6 +157,23 @@ pub struct StandardMaterial {
/// mesh shapes without having to fine tune the thickness, consider using the [`NotTransmittedShadowReceiver`](crate::light::NotTransmittedShadowReceiver) component.
pub diffuse_transmission: f32,
/// A map that modulates diffuse transmission via its **A channel**. Multiplied by [`StandardMaterial::diffuse_transmission`]
/// to obtain the final result.
///
/// **Important:** The [`StandardMaterial::diffuse_transmission`] property must be set to a value higher than 0.0,
/// or this texture won't have any effect.
///
/// **Note:** Due to how channels are mapped, you can more efficiently use a single shared texture image
/// for configuring the following:
///
/// - R - `transmission_texture`
/// - G - `thickness_texture`
/// - B - _unused_
/// - A - `diffuse_transmission_texture`
#[texture(17)]
#[sampler(18)]
pub diffuse_transmission_texture: Option<Handle<Image>>,
/// The amount of light transmitted _specularly_ through the material (i.e. via refraction)
///
/// Implemented as a relatively expensive screen-space effect that allows ocluded objects to be seen through the material, while
@ -171,6 +188,23 @@ pub struct StandardMaterial {
/// **Note:** Typically used in conjunction with [`StandardMaterial::thickness`] and [`StandardMaterial::ior`].
pub transmission: f32,
/// A map that modulates specular transmission via its **R channel**. Multiplied by [`StandardMaterial::transmission`]
/// to obtain the final result.
///
/// **Important:** The [`StandardMaterial::transmission`] property must be set to a value higher than 0.0,
/// or this texture won't have any effect.
///
/// **Note:** Due to how channels are mapped, you can more efficiently use a single shared texture image
/// for configuring the following:
///
/// - R - `transmission_texture`
/// - G - `thickness_texture`
/// - B - _unused_
/// - A - `diffuse_transmission_texture`
#[texture(13)]
#[sampler(14)]
pub transmission_texture: Option<Handle<Image>>,
/// Thickness of the volume beneath the material surface.
///
/// When set to `0.0` (the default) the material appears as an infinitely-thin film,
@ -182,6 +216,23 @@ pub struct StandardMaterial {
/// [`StandardMaterial::diffuse_transmission`].
pub thickness: f32,
/// A map that modulates thickness via its G channel. Multiplied by [`StandardMaterial::thickness`]
/// to obtain the final result.
///
/// **Important:** The [`StandardMaterial::thickness`] property must be set to a value higher than 0.0,
/// or this texture won't have any effect.
///
/// **Note:** Due to how channels are mapped, you can more efficiently use a single shared texture image
/// for configuring the following:
///
/// - R - `transmission_texture`
/// - G - `thickness_texture`
/// - B - _unused_
/// - A - `diffuse_transmission_texture`
#[texture(15)]
#[sampler(16)]
pub thickness_texture: Option<Handle<Image>>,
/// The index of refraction of the material
///
/// | Material | Index of Refraction |
@ -403,8 +454,11 @@ impl Default for StandardMaterial {
// <https://google.github.io/filament/Material%20Properties.pdf>
reflectance: 0.5,
diffuse_transmission: 0.0,
diffuse_transmission_texture: None,
transmission: 0.0,
transmission_texture: None,
thickness: 0.0,
thickness_texture: None,
ior: 1.5,
occlusion_texture: None,
normal_map_texture: None,
@ -462,6 +516,9 @@ bitflags::bitflags! {
const FLIP_NORMAL_MAP_Y = (1 << 7);
const FOG_ENABLED = (1 << 8);
const DEPTH_MAP = (1 << 9); // Used for parallax mapping
const TRANSMISSION_TEXTURE = (1 << 10);
const THICKNESS_TEXTURE = (1 << 11);
const DIFFUSE_TRANSMISSION_TEXTURE = (1 << 12);
const ALPHA_MODE_RESERVED_BITS = (Self::ALPHA_MODE_MASK_BITS << Self::ALPHA_MODE_SHIFT_BITS); // ← Bitmask reserving bits for the `AlphaMode`
const ALPHA_MODE_OPAQUE = (0 << Self::ALPHA_MODE_SHIFT_BITS); // ← Values are just sequential values bitshifted into
const ALPHA_MODE_MASK = (1 << Self::ALPHA_MODE_SHIFT_BITS); // the bitmask, and can range from 0 to 7.
@ -548,6 +605,15 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
if self.depth_map.is_some() {
flags |= StandardMaterialFlags::DEPTH_MAP;
}
if self.transmission_texture.is_some() {
flags |= StandardMaterialFlags::TRANSMISSION_TEXTURE;
}
if self.thickness_texture.is_some() {
flags |= StandardMaterialFlags::THICKNESS_TEXTURE;
}
if self.diffuse_transmission_texture.is_some() {
flags |= StandardMaterialFlags::DIFFUSE_TRANSMISSION_TEXTURE;
}
let has_normal_map = self.normal_map_texture.is_some();
if has_normal_map {
if let Some(texture) = images.get(self.normal_map_texture.as_ref().unwrap()) {

View file

@ -63,9 +63,6 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
pbr_input.material.base_color = output_color;
pbr_input.material.reflectance = material.reflectance;
pbr_input.material.diffuse_transmission = material.diffuse_transmission;
pbr_input.material.transmission = material.transmission;
pbr_input.material.thickness = material.thickness;
pbr_input.material.ior = material.ior;
pbr_input.material.flags = material.flags;
pbr_input.material.alpha_cutoff = material.alpha_cutoff;
@ -92,6 +89,24 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
pbr_input.material.metallic = metallic;
pbr_input.material.perceptual_roughness = perceptual_roughness;
var transmission: f32 = material.transmission;
if ((material.flags & STANDARD_MATERIAL_FLAGS_TRANSMISSION_TEXTURE_BIT) != 0u) {
transmission *= textureSample(transmission_texture, transmission_sampler, uv).r;
}
pbr_input.material.transmission = transmission;
var thickness: f32 = material.thickness;
if ((material.flags & STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT) != 0u) {
thickness *= textureSample(thickness_texture, thickness_sampler, uv).g;
}
pbr_input.material.thickness = thickness;
var diffuse_transmission = material.diffuse_transmission;
if ((material.flags & STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT) != 0u) {
diffuse_transmission *= textureSample(diffuse_transmission_texture, diffuse_transmission_sampler, uv).a;
}
pbr_input.material.diffuse_transmission = diffuse_transmission;
var occlusion: f32 = 1.0;
#ifdef VERTEX_UVS
if ((material.flags & STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) {

View file

@ -28,3 +28,15 @@ var normal_map_sampler: sampler;
var depth_map_texture: texture_2d<f32>;
@group(1) @binding(12)
var depth_map_sampler: sampler;
@group(1) @binding(13)
var transmission_texture: texture_2d<f32>;
@group(1) @binding(14)
var transmission_sampler: sampler;
@group(1) @binding(15)
var thickness_texture: texture_2d<f32>;
@group(1) @binding(16)
var thickness_sampler: sampler;
@group(1) @binding(17)
var diffuse_transmission_texture: texture_2d<f32>;
@group(1) @binding(18)
var diffuse_transmission_sampler: sampler;

View file

@ -28,6 +28,9 @@ const STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP: u32 = 64u;
const STANDARD_MATERIAL_FLAGS_FLIP_NORMAL_MAP_Y: u32 = 128u;
const STANDARD_MATERIAL_FLAGS_FOG_ENABLED_BIT: u32 = 256u;
const STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT: u32 = 512u;
const STANDARD_MATERIAL_FLAGS_TRANSMISSION_TEXTURE_BIT: u32 = 1024u;
const STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT: u32 = 2048u;
const STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT: u32 = 4096u;
const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS: u32 = 3758096384u; // (0b111u32 << 29)
const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE: u32 = 0u; // (0u32 << 29)
const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK: u32 = 536870912u; // (1u32 << 29)