mandelbulb
This commit is contained in:
parent
27d27feba7
commit
d1ed3662bc
2 changed files with 66 additions and 27 deletions
|
|
@ -9,13 +9,51 @@ struct VoluMaterial {
|
||||||
mesh_translation: vec3<f32>,
|
mesh_translation: vec3<f32>,
|
||||||
sphere_radius: f32,
|
sphere_radius: f32,
|
||||||
color: vec4<f32>,
|
color: vec4<f32>,
|
||||||
|
model_inverse: mat4x4<f32>,
|
||||||
|
power: f32,
|
||||||
|
iterations: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@group(2) @binding(100)
|
@group(2) @binding(100)
|
||||||
var<storage, read> volu_material: VoluMaterial;
|
var<storage, read> volu_material: VoluMaterial;
|
||||||
|
|
||||||
fn sphere_sdf(p: vec3<f32>, center: vec3<f32>, radius: f32) -> f32 {
|
fn mandelbulb_sdf(p: vec3<f32>) -> f32 {
|
||||||
return length(p - center) - radius;
|
var z = p;
|
||||||
|
var dr = 1.0;
|
||||||
|
var r = 0.0;
|
||||||
|
let power = volu_material.power;
|
||||||
|
let iterations = volu_material.iterations;
|
||||||
|
|
||||||
|
for (var i = 0; i < iterations; i++) {
|
||||||
|
r = length(z);
|
||||||
|
if r > 2.0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let theta = acos(clamp(z.z / r, -1.0, 1.0));
|
||||||
|
let phi = atan2(z.y, z.x);
|
||||||
|
dr = pow(r, power - 1.0) * power * dr + 1.0;
|
||||||
|
|
||||||
|
let zr = pow(r, power);
|
||||||
|
let new_theta = theta * power;
|
||||||
|
let new_phi = phi * power;
|
||||||
|
|
||||||
|
z = zr * vec3<f32>(
|
||||||
|
sin(new_theta) * cos(new_phi),
|
||||||
|
sin(new_theta) * sin(new_phi),
|
||||||
|
cos(new_theta)
|
||||||
|
) + p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.5 * log(max(r, 0.001)) * r / dr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mandelbulb_normal(p: vec3<f32>) -> vec3<f32> {
|
||||||
|
let e = 0.001;
|
||||||
|
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 dz = mandelbulb_sdf(p + vec3<f32>(0.0, 0.0, e)) - mandelbulb_sdf(p - vec3<f32>(0.0, 0.0, e));
|
||||||
|
return normalize(vec3<f32>(dx, dy, dz));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
||||||
|
|
@ -26,7 +64,7 @@ fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
||||||
|
|
||||||
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;
|
||||||
let distance = sphere_sdf(current_pos, volu_material.mesh_translation, volu_material.sphere_radius);
|
let distance = mandelbulb_sdf(current_pos);
|
||||||
|
|
||||||
if distance < epsilon {
|
if distance < epsilon {
|
||||||
return t;
|
return t;
|
||||||
|
|
@ -42,20 +80,6 @@ fn raymarch(ray_origin: vec3<f32>, ray_direction: vec3<f32>) -> f32 {
|
||||||
return -1.0;
|
return -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sphere_normal(p: vec3<f32>) -> vec3<f32> {
|
|
||||||
let epsilon = 0.001;
|
|
||||||
let center = volu_material.mesh_translation;
|
|
||||||
let radius = volu_material.sphere_radius;
|
|
||||||
|
|
||||||
let gradient = vec3<f32>(
|
|
||||||
sphere_sdf(p + vec3<f32>(epsilon, 0.0, 0.0), center, radius) - sphere_sdf(p - vec3<f32>(epsilon, 0.0, 0.0), center, radius),
|
|
||||||
sphere_sdf(p + vec3<f32>(0.0, epsilon, 0.0), center, radius) - sphere_sdf(p - vec3<f32>(0.0, epsilon, 0.0), center, radius),
|
|
||||||
sphere_sdf(p + vec3<f32>(0.0, 0.0, epsilon), center, radius) - sphere_sdf(p - vec3<f32>(0.0, 0.0, epsilon), center, radius)
|
|
||||||
);
|
|
||||||
|
|
||||||
return normalize(gradient);
|
|
||||||
}
|
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fragment(
|
fn fragment(
|
||||||
vertex_output: VertexOutput,
|
vertex_output: VertexOutput,
|
||||||
|
|
@ -66,20 +90,27 @@ fn fragment(
|
||||||
let ray_origin = view.world_position;
|
let ray_origin = view.world_position;
|
||||||
let ray_direction = normalize(in.world_position.xyz - view.world_position);
|
let ray_direction = normalize(in.world_position.xyz - view.world_position);
|
||||||
|
|
||||||
let t = raymarch(ray_origin, ray_direction);
|
let local_origin = (volu_material.model_inverse * vec4<f32>(ray_origin, 1.0)).xyz;
|
||||||
|
let local_direction = normalize((volu_material.model_inverse * vec4<f32>(ray_direction, 0.0)).xyz);
|
||||||
|
|
||||||
|
let t = raymarch(local_origin, local_direction);
|
||||||
|
|
||||||
var out: FragmentOutput;
|
var out: FragmentOutput;
|
||||||
|
|
||||||
if t > 0.0 {
|
if t > 0.0 {
|
||||||
let hit_point = ray_origin + t * ray_direction;
|
let local_hit_point = ray_origin + t * ray_direction;
|
||||||
let normal = sphere_normal(hit_point);
|
let local_normal = mandelbulb_normal(local_hit_point);
|
||||||
|
|
||||||
in.world_position = vec4<f32>(hit_point, 1.0);
|
let world_hit_point = (transpose(volu_material.model_inverse) * vec4<f32>(local_hit_point, 1.0)).xyz;
|
||||||
in.world_normal = normal;
|
let world_normal = normalize((transpose(volu_material.model_inverse) * vec4<f32>(local_normal, 0.0)).xyz);
|
||||||
|
|
||||||
|
in.world_position = vec4<f32>(world_hit_point, 1.0);
|
||||||
|
in.world_normal = world_normal;
|
||||||
|
|
||||||
var pbr_input = pbr_input_from_standard_material(in, is_front);
|
var pbr_input = pbr_input_from_standard_material(in, is_front);
|
||||||
|
|
||||||
pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color);
|
let n = world_normal * 0.5 + 0.5;
|
||||||
|
pbr_input.material.base_color = alpha_discard(pbr_input.material, vec4<f32>(n, 1.0));
|
||||||
|
|
||||||
out.color = apply_pbr_lighting(pbr_input);
|
out.color = apply_pbr_lighting(pbr_input);
|
||||||
|
|
||||||
|
|
|
||||||
16
src/main.rs
16
src/main.rs
|
|
@ -30,6 +30,9 @@ fn setup(
|
||||||
mesh_translation: transform.translation,
|
mesh_translation: transform.translation,
|
||||||
sphere_radius: 1.0,
|
sphere_radius: 1.0,
|
||||||
color: Vec4::default(),
|
color: Vec4::default(),
|
||||||
|
model_inverse: transform.compute_matrix().inverse(),
|
||||||
|
power: 8.0,
|
||||||
|
iterations: 32,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
|
|
@ -49,6 +52,7 @@ fn setup(
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
DirectionalLight::default(),
|
DirectionalLight::default(),
|
||||||
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,
|
||||||
));
|
));
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
|
|
@ -67,14 +71,12 @@ fn rotate_things(mut q: Query<&mut Transform, With<Rotate>>, time: Res<Time>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_volu_material(
|
fn update_volu_material(
|
||||||
mut q: Query<(&mut Transform, &MeshMaterial3d<VoluMaterial>), Changed<Transform>>,
|
q: Query<(&Transform, &MeshMaterial3d<VoluMaterial>), Changed<Transform>>,
|
||||||
mut volu_materials: ResMut<Assets<VoluMaterial>>,
|
mut volu_materials: ResMut<Assets<VoluMaterial>>,
|
||||||
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
mut buffers: ResMut<Assets<ShaderStorageBuffer>>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
) {
|
) {
|
||||||
for (mut transform, material) in q.iter_mut() {
|
for (transform, material) in q.iter() {
|
||||||
transform.translation.y = time.elapsed_secs().sin();
|
|
||||||
|
|
||||||
let volu_material = volu_materials.get_mut(material.0.id()).unwrap();
|
let volu_material = volu_materials.get_mut(material.0.id()).unwrap();
|
||||||
|
|
||||||
let buffer = buffers
|
let buffer = buffers
|
||||||
|
|
@ -87,6 +89,9 @@ fn update_volu_material(
|
||||||
mesh_translation: transform.translation,
|
mesh_translation: transform.translation,
|
||||||
sphere_radius: (elapsed.sin() + 3.) / 4.,
|
sphere_radius: (elapsed.sin() + 3.) / 4.,
|
||||||
color: vec4((elapsed.sin() + 1.) / 2., 0.0, 0.0, 1.0),
|
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);
|
buffer.set_data(volu_storage);
|
||||||
|
|
@ -110,4 +115,7 @@ pub struct VoluStorage {
|
||||||
mesh_translation: Vec3,
|
mesh_translation: Vec3,
|
||||||
sphere_radius: f32,
|
sphere_radius: f32,
|
||||||
color: Vec4,
|
color: Vec4,
|
||||||
|
model_inverse: Mat4,
|
||||||
|
power: f32,
|
||||||
|
iterations: i32,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue