volumetric changing unlighted sphere
This commit is contained in:
parent
6856e6ac38
commit
38513627ca
2 changed files with 93 additions and 42 deletions
|
|
@ -1,30 +1,46 @@
|
||||||
#import bevy_pbr::{
|
#import bevy_pbr::{
|
||||||
forward_io::{VertexOutput, FragmentOutput},
|
forward_io::{VertexOutput, FragmentOutput},
|
||||||
pbr_fragment::pbr_input_from_standard_material,
|
mesh_view_bindings::view,
|
||||||
pbr_functions::{alpha_discard, apply_pbr_lighting, main_pass_post_lighting_processing},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyExtendedMaterial {
|
struct VoluMaterial {
|
||||||
quantize_steps: u32,
|
mesh_translation: vec3<f32>,
|
||||||
|
sphere_radius: f32,
|
||||||
|
color: vec4<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@group(2) @binding(100)
|
@group(2) @binding(100)
|
||||||
var<uniform> my_extended_material: MyExtendedMaterial;
|
var<storage, read> volu_material: VoluMaterial;
|
||||||
|
|
||||||
|
fn raymarch_hit(position_: vec3<f32>, direction: vec3<f32>) -> bool {
|
||||||
|
var position = position_;
|
||||||
|
for (var i = 0; i < 200; i++) {
|
||||||
|
if sphere_hit(position) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
position += direction * 0.01;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sphere_hit(p: vec3<f32>) -> bool {
|
||||||
|
return distance(p, volu_material.mesh_translation) < volu_material.sphere_radius;
|
||||||
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fragment(
|
fn fragment(
|
||||||
in: VertexOutput,
|
in: VertexOutput,
|
||||||
@builtin(front_facing) is_front: bool,
|
@builtin(front_facing) is_front: bool,
|
||||||
) -> FragmentOutput {
|
) -> FragmentOutput {
|
||||||
var pbr_input = pbr_input_from_standard_material(in, is_front);
|
let view_direction = normalize(in.world_position.xyz - view.world_position);
|
||||||
|
|
||||||
pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color);
|
|
||||||
|
|
||||||
var out: FragmentOutput;
|
var out: FragmentOutput;
|
||||||
|
if (raymarch_hit(in.world_position.xyz, view_direction)) {
|
||||||
out.color = apply_pbr_lighting(pbr_input);
|
out.color = volu_material.color;
|
||||||
|
} else {
|
||||||
out.color = main_pass_post_lighting_processing(pbr_input, out.color);
|
out.color = vec4(1.0, 1.0, 1.0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
95
src/main.rs
95
src/main.rs
|
|
@ -1,53 +1,54 @@
|
||||||
//! Demonstrates using a custom extension to the `StandardMaterial` to modify the results of the builtin pbr shader.
|
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
color::palettes::basic::RED,
|
pbr::{ExtendedMaterial, MaterialExtension},
|
||||||
pbr::{ExtendedMaterial, MaterialExtension, OpaqueRendererMethod},
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::render_resource::*,
|
render::{render_resource::*, storage::ShaderStorageBuffer},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This example uses a shader source file from the assets subdirectory
|
|
||||||
const SHADER_ASSET_PATH: &str = "shaders/material.wgsl";
|
const SHADER_ASSET_PATH: &str = "shaders/material.wgsl";
|
||||||
|
|
||||||
|
type VoluMaterial = ExtendedMaterial<StandardMaterial, VoluExtension>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_plugins(MaterialPlugin::<
|
.add_plugins(MaterialPlugin::<VoluMaterial>::default())
|
||||||
ExtendedMaterial<StandardMaterial, MyExtension>,
|
|
||||||
>::default())
|
|
||||||
.add_systems(Startup, setup)
|
.add_systems(Startup, setup)
|
||||||
.add_systems(Update, rotate_things)
|
.add_systems(Update, (rotate_things, update_volu_material))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(
|
fn setup(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, MyExtension>>>,
|
mut materials: ResMut<Assets<VoluMaterial>>,
|
||||||
|
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
||||||
) {
|
) {
|
||||||
// sphere
|
let transform = Transform::from_xyz(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
let storage = buffers.add(ShaderStorageBuffer::from(VoluStorage {
|
||||||
|
mesh_translation: transform.translation,
|
||||||
|
sphere_radius: 1.0,
|
||||||
|
color: Vec4::default(),
|
||||||
|
}));
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Mesh3d(meshes.add(Sphere::new(1.0))),
|
Mesh3d(meshes.add(Cuboid::new(2.0, 2.0, 2.0))),
|
||||||
MeshMaterial3d(materials.add(ExtendedMaterial {
|
MeshMaterial3d(materials.add(ExtendedMaterial {
|
||||||
base: StandardMaterial {
|
base: StandardMaterial {
|
||||||
base_color: RED.into(),
|
alpha_mode: AlphaMode::Blend,
|
||||||
opaque_render_method: OpaqueRendererMethod::Auto,
|
..default()
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
extension: MyExtension { quantize_steps: 3 },
|
extension: VoluExtension { storage },
|
||||||
})),
|
})),
|
||||||
Transform::from_xyz(0.0, 0.5, 0.0),
|
transform,
|
||||||
));
|
|
||||||
|
|
||||||
// light
|
|
||||||
commands.spawn((
|
|
||||||
DirectionalLight::default(),
|
|
||||||
Transform::from_xyz(1.0, 1.0, 1.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
||||||
Rotate,
|
Rotate,
|
||||||
));
|
));
|
||||||
|
|
||||||
// camera
|
commands.spawn((
|
||||||
|
DirectionalLight::default(),
|
||||||
|
Transform::from_xyz(1.0, 1.0, 1.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
));
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Camera3d::default(),
|
Camera3d::default(),
|
||||||
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
|
@ -63,14 +64,48 @@ fn rotate_things(mut q: Query<&mut Transform, With<Rotate>>, time: Res<Time>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]
|
fn update_volu_material(
|
||||||
struct MyExtension {
|
mut q: Query<(&mut Transform, &MeshMaterial3d<VoluMaterial>), Changed<Transform>>,
|
||||||
#[uniform(100)]
|
mut volu_materials: ResMut<Assets<VoluMaterial>>,
|
||||||
quantize_steps: u32,
|
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
for (mut transform, material) in q.iter_mut() {
|
||||||
|
transform.translation.y = time.elapsed_secs().sin();
|
||||||
|
|
||||||
|
let volu_material = volu_materials.get_mut(material.0.id()).unwrap();
|
||||||
|
|
||||||
|
let buffer = buffers
|
||||||
|
.get_mut(volu_material.extension.storage.id())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let elapsed = time.elapsed_secs_wrapped();
|
||||||
|
|
||||||
|
let volu_storage = VoluStorage {
|
||||||
|
mesh_translation: transform.translation,
|
||||||
|
sphere_radius: (elapsed.sin() + 3.) / 4.,
|
||||||
|
color: vec4((elapsed.sin() + 1.) / 2., 0.0, 0.0, 1.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
buffer.set_data(volu_storage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialExtension for MyExtension {
|
#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]
|
||||||
|
struct VoluExtension {
|
||||||
|
#[storage(100, read_only)]
|
||||||
|
storage: Handle<ShaderStorageBuffer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaterialExtension for VoluExtension {
|
||||||
fn fragment_shader() -> ShaderRef {
|
fn fragment_shader() -> ShaderRef {
|
||||||
SHADER_ASSET_PATH.into()
|
SHADER_ASSET_PATH.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(ShaderType, Clone, Default, Debug)]
|
||||||
|
pub struct VoluStorage {
|
||||||
|
mesh_translation: Vec3,
|
||||||
|
sphere_radius: f32,
|
||||||
|
color: Vec4,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue