Compare commits
10 commits
8da858f57f
...
ed64c3f454
| Author | SHA1 | Date | |
|---|---|---|---|
| ed64c3f454 | |||
| 261d9754f6 | |||
| caa31d994e | |||
| 5cd680e4ea | |||
| 42d3a39fe1 | |||
| 2459a3a059 | |||
| 6f5be26ab5 | |||
| a405a24077 | |||
| a9829b700e | |||
| 405d187a29 |
6 changed files with 240 additions and 91 deletions
66
Cargo.lock
generated
66
Cargo.lock
generated
|
|
@ -434,6 +434,51 @@ dependencies = [
|
||||||
"bevy_internal",
|
"bevy_internal",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy-inspector-egui"
|
||||||
|
version = "0.31.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4971e763f289921fd4616418628458bec26a6fc13fe4299c0e4066f39d7ceaa2"
|
||||||
|
dependencies = [
|
||||||
|
"bevy-inspector-egui-derive",
|
||||||
|
"bevy_app",
|
||||||
|
"bevy_asset",
|
||||||
|
"bevy_color",
|
||||||
|
"bevy_core_pipeline",
|
||||||
|
"bevy_ecs",
|
||||||
|
"bevy_egui",
|
||||||
|
"bevy_image",
|
||||||
|
"bevy_log",
|
||||||
|
"bevy_math",
|
||||||
|
"bevy_pbr",
|
||||||
|
"bevy_platform",
|
||||||
|
"bevy_reflect",
|
||||||
|
"bevy_render",
|
||||||
|
"bevy_state",
|
||||||
|
"bevy_time",
|
||||||
|
"bevy_utils",
|
||||||
|
"bevy_window",
|
||||||
|
"bytemuck",
|
||||||
|
"disqualified",
|
||||||
|
"egui",
|
||||||
|
"fuzzy-matcher",
|
||||||
|
"image",
|
||||||
|
"smallvec",
|
||||||
|
"uuid",
|
||||||
|
"winit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy-inspector-egui-derive"
|
||||||
|
version = "0.31.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2656316165dbe2af6b3acaa763332f5dbdd12f809d59f5bf4304e0642a8005c9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_a11y"
|
name = "bevy_a11y"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
|
|
@ -1014,6 +1059,16 @@ dependencies = [
|
||||||
"glam",
|
"glam",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_panorbit_camera"
|
||||||
|
version = "0.26.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca6e15e297754d0bcb7665620c390c4f05665d4ac4ac91b4b5d3c66b9fe1f0e6"
|
||||||
|
dependencies = [
|
||||||
|
"bevy",
|
||||||
|
"bevy_egui",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_pbr"
|
name = "bevy_pbr"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
|
|
@ -1471,7 +1526,9 @@ name = "bevyart"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
|
"bevy-inspector-egui",
|
||||||
"bevy_egui",
|
"bevy_egui",
|
||||||
|
"bevy_panorbit_camera",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2507,6 +2564,15 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuzzy-matcher"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
|
||||||
|
dependencies = [
|
||||||
|
"thread_local",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { version = "0.16.0", features = ["shader_format_wesl"] }
|
bevy = { version = "0.16.0", features = ["shader_format_wesl"] }
|
||||||
|
bevy-inspector-egui = "0.31.0"
|
||||||
bevy_egui = "0.34.1"
|
bevy_egui = "0.34.1"
|
||||||
|
bevy_panorbit_camera = { version = "0.26.0", features = ["bevy_egui"] }
|
||||||
|
|
||||||
# Enable a small amount of optimization in the dev profile.
|
# Enable a small amount of optimization in the dev profile.
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,24 @@
|
||||||
|
|
||||||
struct VoluMaterial {
|
struct VoluMaterial {
|
||||||
mesh_translation: vec3<f32>,
|
mesh_translation: vec3<f32>,
|
||||||
sphere_radius: f32,
|
|
||||||
color: vec4<f32>,
|
|
||||||
model_inverse: mat4x4<f32>,
|
model_inverse: mat4x4<f32>,
|
||||||
power: f32,
|
power: f32,
|
||||||
iterations: i32,
|
iterations: i32,
|
||||||
|
max_distance: f32,
|
||||||
|
max_steps: i32,
|
||||||
|
ray_epsilon: f32,
|
||||||
|
normal_epsilon: f32,
|
||||||
|
scale: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@group(2) @binding(100)
|
@group(2) @binding(100)
|
||||||
var<storage, read> volu_material: VoluMaterial;
|
var<storage, read> volu_material: VoluMaterial;
|
||||||
|
|
||||||
fn mandelbulb_sdf(p: vec3<f32>) -> f32 {
|
fn mandelbulb_sdf(p: vec3<f32>) -> f32 {
|
||||||
var z = p;
|
let scale = volu_material.scale;
|
||||||
|
let p_scaled = p / scale;
|
||||||
|
|
||||||
|
var z = p_scaled;
|
||||||
var dr = 1.0;
|
var dr = 1.0;
|
||||||
var r = 0.0;
|
var r = 0.0;
|
||||||
let power = volu_material.power;
|
let power = volu_material.power;
|
||||||
|
|
@ -42,14 +48,14 @@ fn mandelbulb_sdf(p: vec3<f32>) -> f32 {
|
||||||
sin(new_theta) * cos(new_phi),
|
sin(new_theta) * cos(new_phi),
|
||||||
sin(new_theta) * sin(new_phi),
|
sin(new_theta) * sin(new_phi),
|
||||||
cos(new_theta)
|
cos(new_theta)
|
||||||
) + p;
|
) + p_scaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.5 * log(max(r, 0.001)) * r / dr;
|
return 0.5 * log(max(r, 0.001)) * r / dr * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mandelbulb_normal(p: vec3<f32>) -> vec3<f32> {
|
fn mandelbulb_normal(p: vec3<f32>) -> vec3<f32> {
|
||||||
let e = 0.001;
|
let e = volu_material.normal_epsilon;
|
||||||
let dx = mandelbulb_sdf(p + vec3<f32>(e, 0.0, 0.0)) - mandelbulb_sdf(p - vec3<f32>(e, 0.0, 0.0));
|
let dx = mandelbulb_sdf(p + vec3<f32>(e, 0.0, 0.0)) - mandelbulb_sdf(p - vec3<f32>(e, 0.0, 0.0));
|
||||||
let dy = mandelbulb_sdf(p + vec3<f32>(0.0, e, 0.0)) - mandelbulb_sdf(p - vec3<f32>(0.0, e, 0.0));
|
let dy = mandelbulb_sdf(p + vec3<f32>(0.0, e, 0.0)) - mandelbulb_sdf(p - vec3<f32>(0.0, e, 0.0));
|
||||||
let dz = mandelbulb_sdf(p + vec3<f32>(0.0, 0.0, e)) - mandelbulb_sdf(p - vec3<f32>(0.0, 0.0, e));
|
let dz = mandelbulb_sdf(p + vec3<f32>(0.0, 0.0, e)) - mandelbulb_sdf(p - vec3<f32>(0.0, 0.0, e));
|
||||||
|
|
@ -58,9 +64,9 @@ fn mandelbulb_normal(p: vec3<f32>) -> vec3<f32> {
|
||||||
|
|
||||||
fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
||||||
var t = 0.0;
|
var t = 0.0;
|
||||||
let max_distance = 100.0;
|
let max_distance = volu_material.max_distance;
|
||||||
let max_steps = 128;
|
let max_steps = volu_material.max_steps;
|
||||||
let epsilon = 0.001;
|
let epsilon = volu_material.ray_epsilon;
|
||||||
|
|
||||||
for (var i = 0; i < max_steps; i++) {
|
for (var i = 0; i < max_steps; i++) {
|
||||||
let current_pos = ray_origin + t * ray_direction;
|
let current_pos = ray_origin + t * ray_direction;
|
||||||
|
|
@ -87,7 +93,7 @@ fn fragment(
|
||||||
) -> FragmentOutput {
|
) -> FragmentOutput {
|
||||||
var in = vertex_output;
|
var in = vertex_output;
|
||||||
|
|
||||||
let ray_origin = view.world_position;
|
let ray_origin = in.world_position.xyz;
|
||||||
let ray_direction = normalize(in.world_position.xyz - view.world_position);
|
let ray_direction = normalize(in.world_position.xyz - view.world_position);
|
||||||
|
|
||||||
let local_origin = (volu_material.model_inverse * vec4<f32>(ray_origin, 1.0)).xyz;
|
let local_origin = (volu_material.model_inverse * vec4<f32>(ray_origin, 1.0)).xyz;
|
||||||
|
|
@ -98,7 +104,7 @@ fn fragment(
|
||||||
var out: FragmentOutput;
|
var out: FragmentOutput;
|
||||||
|
|
||||||
if t > 0.0 {
|
if t > 0.0 {
|
||||||
let local_hit_point = ray_origin + t * ray_direction;
|
let local_hit_point = local_origin + t * local_direction;
|
||||||
let local_normal = mandelbulb_normal(local_hit_point);
|
let local_normal = mandelbulb_normal(local_hit_point);
|
||||||
|
|
||||||
let world_hit_point = (transpose(volu_material.model_inverse) * vec4<f32>(local_hit_point, 1.0)).xyz;
|
let world_hit_point = (transpose(volu_material.model_inverse) * vec4<f32>(local_hit_point, 1.0)).xyz;
|
||||||
14
src/camera.rs
Normal file
14
src/camera.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin};
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.add_plugins(PanOrbitCameraPlugin)
|
||||||
|
.add_systems(Startup, setup);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(mut commands: Commands) {
|
||||||
|
commands.spawn((
|
||||||
|
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
PanOrbitCamera::default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
99
src/main.rs
99
src/main.rs
|
|
@ -1,50 +1,44 @@
|
||||||
use bevy::{
|
use bevy::{color::palettes::css::RED, prelude::*, render::storage::ShaderStorageBuffer};
|
||||||
color::palettes::css::RED,
|
use bevy_egui::EguiPlugin;
|
||||||
pbr::{ExtendedMaterial, MaterialExtension},
|
use mandelbulb::{MandelbulbExtension, MandelbulbMaterial, MandelbulbStorage};
|
||||||
prelude::*,
|
|
||||||
render::{render_resource::*, storage::ShaderStorageBuffer},
|
|
||||||
};
|
|
||||||
|
|
||||||
const SHADER_ASSET_PATH: &str = "shaders/material.wgsl";
|
mod camera;
|
||||||
|
mod mandelbulb;
|
||||||
type VoluMaterial = ExtendedMaterial<StandardMaterial, VoluExtension>;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins((
|
||||||
.add_plugins(MaterialPlugin::<VoluMaterial>::default())
|
DefaultPlugins,
|
||||||
|
EguiPlugin {
|
||||||
|
enable_multipass_for_primary_context: false,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.add_plugins((camera::plugin, mandelbulb::plugin))
|
||||||
.add_systems(Startup, setup)
|
.add_systems(Startup, setup)
|
||||||
.add_systems(Update, (rotate_things, update_volu_material))
|
.add_systems(Update, (rotate_things,))
|
||||||
.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<VoluMaterial>>,
|
mut materials: ResMut<Assets<MandelbulbMaterial>>,
|
||||||
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
||||||
) {
|
) {
|
||||||
let transform = Transform::from_xyz(0.0, 0.0, 0.0);
|
let transform = Transform::from_xyz(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
let storage = buffers.add(ShaderStorageBuffer::from(VoluStorage {
|
let storage = buffers.add(ShaderStorageBuffer::from(MandelbulbStorage::default()));
|
||||||
mesh_translation: transform.translation,
|
|
||||||
sphere_radius: 1.0,
|
|
||||||
color: Vec4::default(),
|
|
||||||
model_inverse: transform.compute_matrix().inverse(),
|
|
||||||
power: 8.0,
|
|
||||||
iterations: 32,
|
|
||||||
}));
|
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Mesh3d(meshes.add(Cuboid::new(2.0, 2.0, 2.0))),
|
Mesh3d(meshes.add(Cuboid::new(2.0, 2.0, 2.0))),
|
||||||
MeshMaterial3d(materials.add(ExtendedMaterial {
|
MeshMaterial3d(materials.add(MandelbulbExtension::create_material(
|
||||||
base: StandardMaterial {
|
StandardMaterial {
|
||||||
base_color: RED.into(),
|
base_color: RED.into(),
|
||||||
alpha_mode: AlphaMode::Blend,
|
alpha_mode: AlphaMode::Blend,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
extension: VoluExtension { storage },
|
storage,
|
||||||
})),
|
))),
|
||||||
transform,
|
transform,
|
||||||
Rotate,
|
Rotate,
|
||||||
));
|
));
|
||||||
|
|
@ -54,11 +48,6 @@ fn setup(
|
||||||
Transform::from_xyz(1.0, 1.0, 1.0).looking_at(Vec3::ZERO, Vec3::Y),
|
Transform::from_xyz(1.0, 1.0, 1.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
Rotate,
|
Rotate,
|
||||||
));
|
));
|
||||||
|
|
||||||
commands.spawn((
|
|
||||||
Camera3d::default(),
|
|
||||||
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
|
@ -69,53 +58,3 @@ fn rotate_things(mut q: Query<&mut Transform, With<Rotate>>, time: Res<Time>) {
|
||||||
t.rotate_y(time.delta_secs());
|
t.rotate_y(time.delta_secs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_volu_material(
|
|
||||||
q: Query<(&Transform, &MeshMaterial3d<VoluMaterial>), Changed<Transform>>,
|
|
||||||
mut volu_materials: ResMut<Assets<VoluMaterial>>,
|
|
||||||
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
|
||||||
time: Res<Time>,
|
|
||||||
) {
|
|
||||||
for (transform, material) in q.iter() {
|
|
||||||
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),
|
|
||||||
model_inverse: transform.compute_matrix(),
|
|
||||||
power: 8.0,
|
|
||||||
iterations: 32,
|
|
||||||
};
|
|
||||||
|
|
||||||
buffer.set_data(volu_storage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]
|
|
||||||
struct VoluExtension {
|
|
||||||
#[storage(100, read_only)]
|
|
||||||
storage: Handle<ShaderStorageBuffer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaterialExtension for VoluExtension {
|
|
||||||
fn fragment_shader() -> ShaderRef {
|
|
||||||
SHADER_ASSET_PATH.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(ShaderType, Clone, Default, Debug)]
|
|
||||||
pub struct VoluStorage {
|
|
||||||
mesh_translation: Vec3,
|
|
||||||
sphere_radius: f32,
|
|
||||||
color: Vec4,
|
|
||||||
model_inverse: Mat4,
|
|
||||||
power: f32,
|
|
||||||
iterations: i32,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
122
src/mandelbulb.rs
Normal file
122
src/mandelbulb.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
use bevy::{
|
||||||
|
pbr::{ExtendedMaterial, MaterialExtension},
|
||||||
|
prelude::*,
|
||||||
|
render::{
|
||||||
|
render_resource::{AsBindGroup, ShaderRef, ShaderType},
|
||||||
|
storage::ShaderStorageBuffer,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
|
||||||
|
|
||||||
|
pub type MandelbulbMaterial = ExtendedMaterial<StandardMaterial, MandelbulbExtension>;
|
||||||
|
|
||||||
|
const SHADER_ASSET_PATH: &str = "shaders/mandelbulb.wgsl";
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.add_plugins(MaterialPlugin::<MandelbulbMaterial>::default())
|
||||||
|
.init_resource::<MandelbulbSettings>()
|
||||||
|
.register_type::<MandelbulbSettings>()
|
||||||
|
.add_plugins(ResourceInspectorPlugin::<MandelbulbSettings>::new())
|
||||||
|
.add_systems(Update, update_volu_material);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Reflect)]
|
||||||
|
struct MandelbulbSettings {
|
||||||
|
power: f32,
|
||||||
|
iterations: i32,
|
||||||
|
max_distance: f32,
|
||||||
|
max_steps: i32,
|
||||||
|
ray_epsilon: f32,
|
||||||
|
normal_epsilon: f32,
|
||||||
|
scale: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MandelbulbSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
power: 8.,
|
||||||
|
iterations: 256,
|
||||||
|
max_distance: 2.,
|
||||||
|
max_steps: 128,
|
||||||
|
ray_epsilon: 0.001,
|
||||||
|
normal_epsilon: 0.001,
|
||||||
|
scale: 0.9,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_volu_material(
|
||||||
|
q: Query<(&Transform, &MeshMaterial3d<MandelbulbMaterial>)>,
|
||||||
|
mut volu_materials: ResMut<Assets<MandelbulbMaterial>>,
|
||||||
|
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
||||||
|
settings: Res<MandelbulbSettings>,
|
||||||
|
) {
|
||||||
|
for (transform, material) in q.iter() {
|
||||||
|
let volu_material = volu_materials.get_mut(material.0.id()).unwrap();
|
||||||
|
|
||||||
|
let buffer = buffers
|
||||||
|
.get_mut(volu_material.extension.storage.id())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let MandelbulbSettings {
|
||||||
|
power,
|
||||||
|
iterations,
|
||||||
|
max_distance,
|
||||||
|
max_steps,
|
||||||
|
ray_epsilon,
|
||||||
|
normal_epsilon,
|
||||||
|
scale,
|
||||||
|
} = *settings;
|
||||||
|
|
||||||
|
let volu_storage = MandelbulbStorage {
|
||||||
|
mesh_translation: transform.translation,
|
||||||
|
model_inverse: transform.compute_matrix().inverse(),
|
||||||
|
power,
|
||||||
|
iterations,
|
||||||
|
max_distance,
|
||||||
|
max_steps,
|
||||||
|
ray_epsilon,
|
||||||
|
normal_epsilon,
|
||||||
|
scale,
|
||||||
|
};
|
||||||
|
|
||||||
|
buffer.set_data(volu_storage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]
|
||||||
|
pub struct MandelbulbExtension {
|
||||||
|
#[storage(100, read_only)]
|
||||||
|
storage: Handle<ShaderStorageBuffer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaterialExtension for MandelbulbExtension {
|
||||||
|
fn fragment_shader() -> ShaderRef {
|
||||||
|
SHADER_ASSET_PATH.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MandelbulbExtension {
|
||||||
|
pub fn create_material(
|
||||||
|
base: StandardMaterial,
|
||||||
|
storage: Handle<ShaderStorageBuffer>,
|
||||||
|
) -> MandelbulbMaterial {
|
||||||
|
MandelbulbMaterial {
|
||||||
|
base,
|
||||||
|
extension: Self { storage },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(ShaderType, Clone, Default, Debug)]
|
||||||
|
pub struct MandelbulbStorage {
|
||||||
|
mesh_translation: Vec3,
|
||||||
|
model_inverse: Mat4,
|
||||||
|
power: f32,
|
||||||
|
iterations: i32,
|
||||||
|
max_distance: f32,
|
||||||
|
max_steps: i32,
|
||||||
|
ray_epsilon: f32,
|
||||||
|
normal_epsilon: f32,
|
||||||
|
scale: f32,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue